diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f9c89caa..bb0737d8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,20 @@ # Changelog -All PRs to the Wasmer repository must add to this file. - -Blocks of changes will separated by version increments. - ## **[Unreleased]** +- [#921](https://github.com/wasmerio/wasmer/pull/921) In LLVM backend, annotate all memory accesses with TBAA metadata. +- [#883](https://github.com/wasmerio/wasmer/pull/883) Allow floating point operations to have arbitrary inputs, even including SNaNs. +- [#856](https://github.com/wasmerio/wasmer/pull/856) Expose methods in the runtime C API to get a WASI import object + +## 0.9.0 - 2019-10-23 + +Special thanks to @alocquet for their contributions! + +- [#898](https://github.com/wasmerio/wasmer/pull/898) State tracking is now disabled by default in the LLVM backend. It can be enabled with `--track-state`. +- [#861](https://github.com/wasmerio/wasmer/pull/861) Add descriptions to `unimplemented!` macro in various places +- [#897](https://github.com/wasmerio/wasmer/pull/897) Removes special casing of stdin, stdout, and stderr in WASI. Closing these files now works. Removes `stdin`, `stdout`, and `stderr` from `WasiFS`, replaced by the methods `stdout`, `stdout_mut`, and so on. +- [#863](https://github.com/wasmerio/wasmer/pull/863) Fix min and max for cases involving NaN and negative zero when using the LLVM backend. + - [#858](https://github.com/wasmerio/wasmer/pull/858) Minor panic fix when wasmer binary with `loader` option run a module without exported `_start` function ## 0.8.0 - 2019-10-02 diff --git a/Cargo.lock b/Cargo.lock index 9c0d362ed..9012e4f6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,10 +23,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -34,50 +34,28 @@ name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bincode" -version = "1.1.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bindgen" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "which 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bitflags" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -86,7 +64,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -98,7 +76,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -108,27 +86,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "c2-chacha" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "capstone" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "capstone-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "capstone-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -136,8 +97,8 @@ name = "cargo_toml" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -153,43 +114,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cexpr" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "clang-sys" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "clap" version = "2.33.0" @@ -197,7 +140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -209,7 +152,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -217,7 +160,7 @@ name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -242,10 +185,10 @@ dependencies = [ "cranelift-codegen-meta 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen-shared 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -288,18 +231,18 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -311,7 +254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -328,11 +271,11 @@ name = "crossbeam-epoch" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -349,7 +292,7 @@ name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -361,8 +304,8 @@ dependencies = [ "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -375,11 +318,11 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -395,7 +338,7 @@ name = "dynasm" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -416,7 +359,7 @@ dependencies = [ [[package]] name = "either" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -428,24 +371,12 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "env_logger" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "erased-serde" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -454,7 +385,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -464,26 +395,26 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -503,11 +434,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "generational-arena" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -520,11 +451,11 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -533,9 +464,9 @@ name = "ghost" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -563,7 +494,15 @@ name = "heck" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -572,31 +511,24 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "humantime" +name = "indexmap" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "indexmap" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inkwell" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#8f480124663b812ee76cd4370f3ee170135b9d0e" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#bd0d09a8041dc2217f698cd3631b6d4d4c0e696b" dependencies = [ - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "llvm-sys 80.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -604,7 +536,7 @@ dependencies = [ [[package]] name = "inkwell_internal_macros" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#8f480124663b812ee76cd4370f3ee170135b9d0e" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#bd0d09a8041dc2217f698cd3631b6d4d4c0e696b" dependencies = [ "cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -617,7 +549,7 @@ name = "inventory" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ctor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -627,17 +559,17 @@ name = "inventory-impl" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itertools" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -665,26 +597,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.62" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "libloading" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "llvm-sys" version = "80.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -702,7 +625,7 @@ name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -715,7 +638,7 @@ name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -723,7 +646,7 @@ name = "memmap" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -732,13 +655,13 @@ name = "memmap" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memoffset" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -749,41 +672,33 @@ name = "nix" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nodrop" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num_cpus" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -800,7 +715,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -810,8 +725,8 @@ version = "0.1.0" dependencies = [ "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime 0.8.0", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime 0.9.0", + "wasmer-runtime-core 0.9.0", ] [[package]] @@ -837,20 +752,15 @@ name = "parking_lot_core" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "plain" version = "0.2.3" @@ -862,7 +772,7 @@ version = "0.1.0" [[package]] name = "ppv-lite86" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -870,9 +780,9 @@ name = "proc-macro-error" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -885,17 +795,12 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "quote" version = "0.3.15" @@ -914,7 +819,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -922,8 +827,8 @@ name = "rand" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -934,7 +839,7 @@ name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -956,7 +861,7 @@ name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -974,7 +879,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -994,8 +899,8 @@ name = "raw-cpuid" version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1005,7 +910,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1018,7 +923,7 @@ dependencies = [ "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1066,14 +971,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc-hash" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rustc_version" version = "0.2.3" @@ -1084,7 +981,7 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1134,10 +1031,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1146,7 +1043,7 @@ version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1154,37 +1051,32 @@ name = "serde_bytes" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "shlex" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "smallvec" -version = "0.6.10" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1199,23 +1091,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1240,10 +1132,10 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1258,13 +1150,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.10.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1277,9 +1169,9 @@ name = "target-lexicon" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1287,22 +1179,14 @@ name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "termcolor" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -1324,7 +1208,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1334,8 +1218,8 @@ name = "tinytemplate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1343,15 +1227,15 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1367,7 +1251,7 @@ dependencies = [ "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "typetag-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1376,14 +1260,14 @@ name = "typetag-impl" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-segmentation" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1411,11 +1295,6 @@ name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "void" version = "1.0.2" @@ -1426,9 +1305,9 @@ name = "wabt" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1437,7 +1316,7 @@ name = "wabt-sys" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1459,52 +1338,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasmer" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-dev-utils 0.8.0", - "wasmer-emscripten 0.8.0", - "wasmer-emscripten-tests 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-dev-utils 0.9.0", + "wasmer-emscripten 0.9.0", + "wasmer-emscripten-tests 0.9.0", "wasmer-kernel-loader 0.1.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-middleware-common 0.8.0", - "wasmer-middleware-common-tests 0.8.0", - "wasmer-runtime 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", - "wasmer-wasi 0.8.0", - "wasmer-wasi-tests 0.8.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-middleware-common 0.9.0", + "wasmer-middleware-common-tests 0.9.0", + "wasmer-runtime 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", + "wasmer-wasi 0.9.0", + "wasmer-wasi-tests 0.9.0", ] [[package]] name = "wasmer-clif-backend" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-native 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-fork-frontend 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-fork-wasm 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", - "wasmer-win-exception-handler 0.8.0", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-runtime-core 0.9.0", + "wasmer-win-exception-handler 0.9.0", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1515,7 +1394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cranelift-codegen 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1526,231 +1405,231 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cranelift-codegen 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-fork-frontend 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-dev-utils" -version = "0.8.0" +version = "0.9.0" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-emscripten" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime-core 0.9.0", ] [[package]] name = "wasmer-emscripten-tests" -version = "0.8.0" +version = "0.9.0" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-dev-utils 0.8.0", - "wasmer-emscripten 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-dev-utils 0.9.0", + "wasmer-emscripten 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", ] [[package]] name = "wasmer-kernel-loader" version = "0.1.0" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-runtime-core 0.9.0", ] [[package]] name = "wasmer-llvm-backend" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "capstone 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "inkwell 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-runtime-core 0.9.0", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-middleware-common" -version = "0.8.0" +version = "0.9.0" dependencies = [ - "wasmer-runtime-core 0.8.0", + "wasmer-runtime-core 0.9.0", ] [[package]] name = "wasmer-middleware-common-tests" -version = "0.8.0" +version = "0.9.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-middleware-common 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-middleware-common 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", ] [[package]] name = "wasmer-runtime" -version = "0.8.0" +version = "0.9.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", ] [[package]] name = "wasmer-runtime-c-api" -version = "0.8.0" +version = "0.9.0" dependencies = [ "cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime 0.8.0", - "wasmer-runtime-core 0.8.0", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-runtime 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-wasi 0.9.0", ] [[package]] name = "wasmer-runtime-core" -version = "0.8.0" +version = "0.9.0" dependencies = [ - "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasmer-runtime-core-tests" +version = "0.9.0" +dependencies = [ + "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-clif-backend 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", +] + [[package]] name = "wasmer-singlepass-backend" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "dynasm 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-runtime-core 0.9.0", ] [[package]] name = "wasmer-spectests" -version = "0.8.0" +version = "0.9.0" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", ] [[package]] name = "wasmer-wasi" -version = "0.8.0" +version = "0.9.0" dependencies = [ - "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generational-arena 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "generational-arena 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime-core 0.9.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-wasi-tests" -version = "0.8.0" +version = "0.9.0" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-dev-utils 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-runtime 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", - "wasmer-wasi 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-dev-utils 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", + "wasmer-wasi 0.9.0", ] [[package]] name = "wasmer-win-exception-handler" -version = "0.8.0" +version = "0.9.0" dependencies = [ - "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-runtime-core 0.9.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmparser" -version = "0.39.1" +version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "which" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "winapi" version = "0.2.8" @@ -1788,38 +1667,24 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "wincolor" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" -"checksum bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum capstone 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "031ba51c39151a1d6336ec859646153187204b0147c7b3f6fe2de636f1b8dbb3" -"checksum capstone-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fae25eddcb80e24f98c35952c37a91ff7f8d0f60dbbdafb9763e8d5cc566b8d7" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "097f5ce64ba566a83d9d914fd005de1e5937fdd57d8c5d99a7593040955d75a9" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" "checksum cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd" -"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" -"checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853" +"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" @@ -1838,42 +1703,40 @@ dependencies = [ "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" -"checksum ctor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5b6b2f4752cc29efbfd03474c532ce8f916f2d44ec5bb8c21f93bc76e5365528" +"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum dynasm 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f36d49ab6f8ecc642d2c6ee10fda04ba68003ef0277300866745cdde160e6b40" "checksum dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c408a211e7f5762829f5e46bdff0c14bc3b1517a21a4bb781c716bf88b0c68" -"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7798e7da2d4cb0d6d6fc467e8d6b5bf247e9e989f786dde1732d79899c32bb10" -"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generational-arena 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "921c3803adaeb9f9639de5149d9f0f9f4b79f00c423915b701db2e02ed80b9ce" +"checksum generational-arena 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd04ad33021a0409d3f1afbfb89d9f02c10caee73c28f5ac197474dd53e7cf7c" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" "checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" +"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" "checksum inkwell 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)" = "" "checksum inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)" = "" "checksum inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" "checksum inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9" -"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" +"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" -"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum llvm-sys 80.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2110cd4daf9cd8e39dd3b933b1a2a2ac7315e91f7c92b3a20beab526c63b5978" "checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" @@ -1881,23 +1744,20 @@ dependencies = [ "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" +"checksum memoffset 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a85c1a8c329f11437034d7313dca647c79096523533a1c79e86f1d0f657c7cc" "checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum num_cpus 1.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "155394f924cdddf08149da25bfb932d226b4a593ca7468b08191ff6335941af5" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" @@ -1918,51 +1778,47 @@ dependencies = [ "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" +"checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" "checksum serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d733da87e79faaac25616e33d26299a41143fd4cd42746cbb0e91d8feea243fd" "checksum serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45af0182ff64abaeea290235eb67da3825a576c5d53e642c4d5b652e12e6effc" -"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" -"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" -"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" -"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" +"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" +"checksum smallvec 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "533e29e15d0748f28afbaf4ff7cab44d73e483a8e50b38c40bd13b7f3d48f542" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe8d3289b63ef2f196d89e7701f986583c0895e764b78f052a55b9b5d34d84a" -"checksum structopt-derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f3add731f5b4fb85931d362a3c92deb1ad7113649a8d51701fb257673705f122" +"checksum structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f66a4c0ddf7aee4677995697366de0749b0139057342eccbb609b12d0affc" +"checksum structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fe0c13e476b4e21ff7f5c4ace3818b6d7bdc16897c31c73862471bc1663acae" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724" +"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebb2c484029d695fb68a06d80e1536c68d491b3e0cf874c66abed255e831cfe" "checksum typetag-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b63fd4799e4d0ec5cf0b055ebb8e2c3a657bbf76a84f6edc77ca60780e000204" -"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" +"checksum unicode-segmentation 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49f5526225fd8b77342d5986ab5f6055552e9c0776193b5b63fd53b46debfad7" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5c5c1286c6e578416982609f47594265f9d489f9b836157d403ad605a46693" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" @@ -1970,12 +1826,10 @@ dependencies = [ "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" "checksum wasmer-clif-fork-frontend 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0cf2f552a9c1fda0555087170424bd8fedc63a079a97bb5638a4ef9b0d9656aa" "checksum wasmer-clif-fork-wasm 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0073b512e1af5948d34be7944b74c747bbe735ccff2e2f28c26ed4c90725de8e" -"checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" -"checksum which 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "240a31163872f7e8e49f35b42b58485e35355b07eb009d9f3686733541339a69" +"checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" diff --git a/Cargo.toml b/Cargo.toml index 4d619059e..2a47f943d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer" -version = "0.8.0" +version = "0.9.0" authors = ["The Wasmer Engineering Team "] edition = "2018" repository = "https://github.com/wasmerio/wasmer" @@ -43,6 +43,7 @@ members = [ "lib/singlepass-backend", "lib/runtime", "lib/runtime-core", + "lib/runtime-core-tests", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", diff --git a/Makefile b/Makefile index 58b85dbb1..e8d11bed0 100644 --- a/Makefile +++ b/Makefile @@ -89,12 +89,15 @@ wasitests: wasitests-unit wasitests-singlepass wasitests-cranelift wasitests-llv # Backends singlepass: spectests-singlepass emtests-singlepass middleware-singlepass wasitests-singlepass cargo test -p wasmer-singlepass-backend --release + cargo test -p wasmer-runtime-core-tests --release --no-default-features --features backend-singlepass cranelift: spectests-cranelift emtests-cranelift middleware-cranelift wasitests-cranelift cargo test -p wasmer-clif-backend --release + cargo test -p wasmer-runtime-core-tests --release llvm: spectests-llvm emtests-llvm wasitests-llvm cargo test -p wasmer-llvm-backend --release + cargo test -p wasmer-runtime-core-tests --release --no-default-features --features backend-llvm # All tests @@ -105,8 +108,23 @@ capi: test-capi: capi cargo test -p wasmer-runtime-c-api --release +capi-test: test-capi + test-rest: - cargo test --release --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-wasi --exclude wasmer-middleware-common --exclude wasmer-middleware-common-tests --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-llvm-backend --exclude wasmer-wasi-tests --exclude wasmer-emscripten-tests + cargo test --release \ + --all \ + --exclude wasmer-runtime-c-api \ + --exclude wasmer-emscripten \ + --exclude wasmer-spectests \ + --exclude wasmer-wasi \ + --exclude wasmer-middleware-common \ + --exclude wasmer-middleware-common-tests \ + --exclude wasmer-singlepass-backend \ + --exclude wasmer-clif-backend \ + --exclude wasmer-llvm-backend \ + --exclude wasmer-wasi-tests \ + --exclude wasmer-emscripten-tests \ + --exclude wasmer-runtime-core-tests circleci-clean: @if [ ! -z "${CIRCLE_JOB}" ]; then rm -f /home/circleci/project/target/debug/deps/libcranelift_wasm* && rm -f /Users/distiller/project/target/debug/deps/libcranelift_wasm*; fi; @@ -140,20 +158,65 @@ install: # Checks check-bench-singlepass: - cargo bench --all --no-run --no-default-features --features "backend-singlepass" \ + cargo check --benches --all --no-default-features --features "backend-singlepass" \ --exclude wasmer-clif-backend --exclude wasmer-llvm-backend --exclude wasmer-kernel-loader check-bench-clif: - cargo bench --all --no-run --no-default-features --features "backend-cranelift" \ + cargo check --benches --all --no-default-features --features "backend-cranelift" \ --exclude wasmer-singlepass-backend --exclude wasmer-llvm-backend --exclude wasmer-kernel-loader \ --exclude wasmer-middleware-common-tests check-bench-llvm: - cargo bench --all --no-run --no-default-features --features "backend-llvm" \ + cargo check --benches --all --no-default-features --features "backend-llvm" \ --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-kernel-loader check-bench: check-bench-singlepass check-bench-llvm +# TODO: We wanted `--workspace --exclude wasmer-runtime`, but can't due +# to https://github.com/rust-lang/cargo/issues/6745 . +NOT_RUNTIME_CRATES = -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests +RUNTIME_CHECK = cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features check: check-bench - cargo check --release --features backend-singlepass,backend-llvm,loader-kernel,debug + cargo check $(NOT_RUNTIME_CRATES) + cargo check --release $(NOT_RUNTIME_CRATES) + cargo check --all-features $(NOT_RUNTIME_CRATES) + cargo check --release --all-features $(NOT_RUNTIME_CRATES) + # wasmer-runtime doesn't work with all backends enabled at once. + # + # We test using manifest-path directly so as to disable the default. + # `--no-default-features` only disables the default features in the + # current package, not the package specified by `-p`. This is + # intentional. + # + # Test default features, test 'debug' feature only in non-release + # builds, test as many combined features as possible with each backend + # as default, and test a minimal set of features with only one backend + # at a time. + cargo check --manifest-path lib/runtime/Cargo.toml + cargo check --release --manifest-path lib/runtime/Cargo.toml + + $(RUNTIME_CHECK) \ + --features=cranelift,cache,debug,llvm,singlepass,default-backend-singlepass + $(RUNTIME_CHECK) --release \ + --features=cranelift,cache,llvm,singlepass,default-backend-singlepass + $(RUNTIME_CHECK) \ + --features=cranelift,cache,debug,llvm,singlepass,default-backend-cranelift + $(RUNTIME_CHECK) --release \ + --features=cranelift,cache,llvm,singlepass,default-backend-cranelift + $(RUNTIME_CHECK) \ + --features=cranelift,cache,debug,llvm,singlepass,default-backend-llvm + $(RUNTIME_CHECK) --release \ + --features=cranelift,cache,llvm,singlepass,default-backend-llvm + $(RUNTIME_CHECK) \ + --features=singlepass,default-backend-singlepass,debug + $(RUNTIME_CHECK) --release \ + --features=singlepass,default-backend-singlepass + $(RUNTIME_CHECK) \ + --features=cranelift,default-backend-cranelift,debug + $(RUNTIME_CHECK) --release \ + --features=cranelift,default-backend-cranelift + $(RUNTIME_CHECK) \ + --features=llvm,default-backend-llvm,debug + $(RUNTIME_CHECK) --release \ + --features=llvm,default-backend-llvm # Release release: diff --git a/README.md b/README.md index e69fe2d1c..7e7f39cb1 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ Wasmer runtime can be used as a library embedded in different languages, so you | ![PHP logo](./docs/assets/languages/php.svg) | [**PHP**](https://github.com/wasmerio/php-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/php-ext-wasm?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/php-ext-wasm?style=flat-square) | | ![Ruby logo](./docs/assets/languages/ruby.svg) | [**Ruby**](https://github.com/wasmerio/ruby-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/gem/v/wasmer?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/ruby-ext-wasm?style=flat-square) | | ![Postgres logo](./docs/assets/languages/postgres.svg) | [**Postgres**](https://github.com/wasmerio/postgres-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/postgres-ext-wasm?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/postgres-ext-wasm?style=flat-square) | +| ![JS Logo](./docs/assets/languages/js.svg) | [**JavaScript**](https://github.com/wasmerio/wasmer-js) | Wasmer | actively developed | ![last release](https://img.shields.io/npm/v/@wasmer/wasi?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer-js?style=flat-square) | | ![C# logo](./docs/assets/languages/csharp.svg) | [**C#/.Net**](https://github.com/migueldeicaza/WasmerSharp) | [Miguel de Icaza](https://github.com/migueldeicaza) | actively developed | ![last release](https://img.shields.io/nuget/v/WasmerSharp?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/migueldeicaza/WasmerSharp?style=flat-square) | | ![R logo](./docs/assets/languages/r.svg) | [**R**](https://github.com/dirkschumacher/wasmr) | [Dirk Schumacher](https://github.com/dirkschumacher) | actively developed | | ![number of Github stars](https://img.shields.io/github/stars/dirkschumacher/wasmr?style=flat-square) | | ![Swift logo](./docs/assets/languages/swift.svg) | [**Swift**](https://github.com/markmals/swift-ext-wasm) | [Mark Malström](https://github.com/markmals/) | passively maintained | | ![number of Github stars](https://img.shields.io/github/stars/markmals/swift-ext-wasm?style=flat-square) | diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c0c350d54..db05b2d34 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -60,6 +60,10 @@ jobs: cat /proc/meminfo displayName: System info - Extended (Linux) condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) + - bash: | + sysctl -a | grep machdep.cpu + displayName: System info - Extended (Mac) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) - bash: make test displayName: Tests (*nix) condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT'))) diff --git a/docs/assets/languages/js.svg b/docs/assets/languages/js.svg new file mode 100755 index 000000000..6a186f383 --- /dev/null +++ b/docs/assets/languages/js.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docs/feature_matrix.md b/docs/feature_matrix.md index cdb6ff8ad..81602762b 100644 --- a/docs/feature_matrix.md +++ b/docs/feature_matrix.md @@ -11,6 +11,17 @@ | OSR | 🔄 | ❓ | ❓ | | SIMD | ⬜ | ⬜ | ✅ | | WASI | ✅ | ✅ | ✅ | +| WASMER_BACKTRACE | ✅ | ⬜ | ⬜ | + +## Operating System +|   | GNU Linux | Mac OSX | Windows NT | +| - | :-: | :-: | :-: | +| Cranelift Backend | ✅ | ✅ | ✅ | +| LLVM Backend | ✅ | ✅ | ✅ | +| Singlepass Backend | [#347](https://github.com/wasmerio/wasmer/issues/347) | ✅ | ✅ | +| WASI | ✅ | ✅ | ✅* | + +* `poll_fd` is not fully implemented for Windows yet ## Language integration @@ -18,8 +29,14 @@ TODO: define a set of features that are relevant and mark them here Current ideas: -- WASI FS API - Callbacks -- Exiting early in hostcall - Metering - Caching + +> TODO: expand this table, it's focused on new features that we haven't implemented yet and doesn't list all language integrations + +|   | Rust | C / C++ | Go | Python | Ruby | +| - | :-: | :-: | :-: | :-: | :-: | +| Terminate in host call | ✅ | ⬜ | ⬜ | ⬜ | ⬜ | +| WASI | ✅ | ✅ | 🔄 | ⬜ | ⬜ | +| WASI FS API | ✅ | ⬜ | ⬜ | ⬜ | ⬜ | diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index c940b1b6e..22af9de03 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-clif-backend" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime Cranelift compiler backend" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,7 +9,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } cranelift-native = "0.44.0" cranelift-codegen = "0.44.0" cranelift-entity = "0.44.0" @@ -35,7 +35,7 @@ version = "0.0.7" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] } -wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.8.0" } +wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.9.0" } [features] debug = ["wasmer-runtime-core/debug"] diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index b2ccc6652..f1d8489da 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -128,166 +128,6 @@ impl ModuleCodeGenerator .state .initialize(&builder.func.signature, exit_block); - #[cfg(feature = "debug")] - { - use cranelift_codegen::cursor::{Cursor, FuncCursor}; - use cranelift_codegen::ir::InstBuilder; - let entry_ebb = func.layout.entry_block().unwrap(); - let ebb = func.dfg.make_ebb(); - func.layout.insert_ebb(ebb, entry_ebb); - let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(ebb); - let params = pos.func.dfg.ebb_params(entry_ebb).to_vec(); - - let new_ebb_params: Vec<_> = params - .iter() - .map(|¶m| { - pos.func - .dfg - .append_ebb_param(ebb, pos.func.dfg.value_type(param)) - }) - .collect(); - - let start_debug = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("strtdbug"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let end_debug = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ir::AbiParam::special( - ir::types::I64, - ir::ArgumentPurpose::VMContext, - )], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("enddbug"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let i32_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("i32print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let i64_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I64), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("i64print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let f32_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::F32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("f32print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let f64_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::F64), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("f64print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let vmctx = pos - .func - .special_param(ir::ArgumentPurpose::VMContext) - .expect("missing vmctx parameter"); - - let func_index = pos.ins().iconst( - ir::types::I32, - func_index.index() as i64 + self.module.info.imported_functions.len() as i64, - ); - - pos.ins().call(start_debug, &[vmctx, func_index]); - - for param in new_ebb_params.iter().cloned() { - match pos.func.dfg.value_type(param) { - ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]), - ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]), - ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]), - ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]), - _ => unimplemented!(), - }; - } - - pos.ins().call(end_debug, &[vmctx]); - - pos.ins().jump(entry_ebb, new_ebb_params.as_slice()); - } - self.functions.push(func_env); Ok(self.functions.last_mut().unwrap()) } diff --git a/lib/clif-backend/src/relocation.rs b/lib/clif-backend/src/relocation.rs index bb07c7c59..a86bdeec9 100644 --- a/lib/clif-backend/src/relocation.rs +++ b/lib/clif-backend/src/relocation.rs @@ -105,7 +105,7 @@ impl binemit::RelocSink for RelocSink { _ebb_offset: binemit::CodeOffset, ) { // This should use the `offsets` field of `ir::Function`. - unimplemented!(); + unimplemented!("RelocSink::reloc_ebb"); } fn reloc_external( &mut self, @@ -146,7 +146,7 @@ impl binemit::RelocSink for RelocSink { DYNAMIC_MEM_GROW => VmCallKind::DynamicMemoryGrow, DYNAMIC_MEM_SIZE => VmCallKind::DynamicMemorySize, - _ => unimplemented!(), + _ => unimplemented!("reloc_external VmCall::Local {}", index), })), IMPORT_NAMESPACE => RelocationType::VmCall(VmCall::Import(match index { STATIC_MEM_GROW => VmCallKind::StaticMemoryGrow, @@ -157,10 +157,10 @@ impl binemit::RelocSink for RelocSink { DYNAMIC_MEM_GROW => VmCallKind::DynamicMemoryGrow, DYNAMIC_MEM_SIZE => VmCallKind::DynamicMemorySize, - _ => unimplemented!(), + _ => unimplemented!("reloc_external VmCall::Import {}", index), })), SIG_NAMESPACE => RelocationType::Signature(SigIndex::new(index as usize)), - _ => unimplemented!(), + _ => unimplemented!("reloc_external SigIndex {}", index), }; self.external_relocs.push(ExternalRelocation { reloc, @@ -204,7 +204,7 @@ impl binemit::RelocSink for RelocSink { } fn reloc_constant(&mut self, _: u32, _: cranelift_codegen::binemit::Reloc, _: u32) { - unimplemented!() + unimplemented!("RelocSink::reloc_constant") } fn reloc_jt( @@ -213,7 +213,7 @@ impl binemit::RelocSink for RelocSink { _reloc: binemit::Reloc, _jt: ir::JumpTable, ) { - unimplemented!(); + unimplemented!("RelocSink::reloc_jt"); } } diff --git a/lib/clif-backend/src/resolver.rs b/lib/clif-backend/src/resolver.rs index 7a868f35e..efc038d58 100644 --- a/lib/clif-backend/src/resolver.rs +++ b/lib/clif-backend/src/resolver.rs @@ -1,32 +1,31 @@ -use crate::{cache::BackendCache, trampoline::Trampolines}; use crate::{ + cache::BackendCache, libcalls, relocation::{ ExternalRelocation, LibCall, LocalRelocation, LocalTrapSink, Reloc, RelocSink, RelocationType, TrapSink, VmCall, VmCallKind, }, signal::HandlerData, + trampoline::Trampolines, }; -use rayon::prelude::*; - use byteorder::{ByteOrder, LittleEndian}; use cranelift_codegen::{ binemit::{Stackmap, StackmapSink}, ir, isa, Context, }; +use rayon::prelude::*; use std::{ mem, ptr::{write_unaligned, NonNull}, sync::Arc, }; - -use wasmer_runtime_core::cache::Error as CacheError; use wasmer_runtime_core::{ self, backend::{ sys::{Memory, Protect}, SigRegistry, }, + cache::Error as CacheError, error::{CompileError, CompileResult}, module::ModuleInfo, structures::{Map, SliceMap, TypedIndex}, @@ -250,17 +249,9 @@ impl FuncResolverBuilder { #[cfg(not(target_os = "windows"))] LibCall::Probestack => __rust_probestack as isize, }, - RelocationType::Intrinsic(ref name) => match name.as_str() { - "i32print" => i32_print as isize, - "i64print" => i64_print as isize, - "f32print" => f32_print as isize, - "f64print" => f64_print as isize, - "strtdbug" => start_debug as isize, - "enddbug" => end_debug as isize, - _ => Err(CompileError::InternalError { - msg: format!("unexpected intrinsic: {}", name), - })?, - }, + RelocationType::Intrinsic(ref name) => Err(CompileError::InternalError { + msg: format!("unexpected intrinsic: {}", name), + })?, RelocationType::VmCall(vmcall) => match vmcall { VmCall::Local(kind) => match kind { VmCallKind::StaticMemoryGrow | VmCallKind::SharedStaticMemoryGrow => { @@ -371,28 +362,3 @@ impl FuncResolver { fn round_up(n: usize, multiple: usize) -> usize { (n + multiple - 1) & !(multiple - 1) } - -extern "C" fn i32_print(_ctx: &mut vm::Ctx, n: i32) { - eprint!(" i32: {},", n); -} -extern "C" fn i64_print(_ctx: &mut vm::Ctx, n: i64) { - eprint!(" i64: {},", n); -} -extern "C" fn f32_print(_ctx: &mut vm::Ctx, n: f32) { - eprint!(" f32: {},", n); -} -extern "C" fn f64_print(_ctx: &mut vm::Ctx, n: f64) { - eprint!(" f64: {},", n); -} -extern "C" fn start_debug(ctx: &mut vm::Ctx, func_index: u32) { - if let Some(symbol_map) = unsafe { ctx.borrow_symbol_map() } { - if let Some(fn_name) = symbol_map.get(&func_index) { - eprint!("func ({} ({})), args: [", fn_name, func_index); - return; - } - } - eprint!("func ({}), args: [", func_index); -} -extern "C" fn end_debug(_ctx: &mut vm::Ctx) { - eprintln!(" ]"); -} diff --git a/lib/clif-backend/src/signal/mod.rs b/lib/clif-backend/src/signal/mod.rs index 3facce2ad..116da3f56 100644 --- a/lib/clif-backend/src/signal/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -1,12 +1,14 @@ -use crate::relocation::{TrapData, TrapSink}; -use crate::resolver::FuncResolver; -use crate::trampoline::Trampolines; +use crate::{ + relocation::{TrapData, TrapSink}, + resolver::FuncResolver, + trampoline::Trampolines, +}; use libc::c_void; use std::{any::Any, cell::Cell, ptr::NonNull, sync::Arc}; use wasmer_runtime_core::{ backend::RunnableModule, module::ModuleInfo, - typed_func::{Wasm, WasmTrapInfo}, + typed_func::{Trampoline, Wasm, WasmTrapInfo}, types::{LocalFuncIndex, SigIndex}, vm, }; @@ -59,7 +61,7 @@ impl RunnableModule for Caller { fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { unsafe extern "C" fn invoke( - trampoline: unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64), + trampoline: Trampoline, ctx: *mut vm::Ctx, func: NonNull, args: *const u64, diff --git a/lib/clif-backend/src/signal/unix.rs b/lib/clif-backend/src/signal/unix.rs index 39f3aa893..79b6619d3 100644 --- a/lib/clif-backend/src/signal/unix.rs +++ b/lib/clif-backend/src/signal/unix.rs @@ -98,7 +98,10 @@ pub fn call_protected( }, Ok(SIGSEGV) | Ok(SIGBUS) => WasmTrapInfo::MemoryOutOfBounds, Ok(SIGFPE) => WasmTrapInfo::IllegalArithmetic, - _ => unimplemented!(), + _ => unimplemented!( + "WasmTrapInfo::Unknown signal:{:?}", + Signal::from_c_int(signum) + ), })) } else { let signal = match Signal::from_c_int(signum) { diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs index d755cd575..363119c6e 100644 --- a/lib/clif-backend/src/signal/windows.rs +++ b/lib/clif-backend/src/signal/windows.rs @@ -1,24 +1,30 @@ -use crate::relocation::{TrapCode, TrapData}; -use crate::signal::{CallProtError, HandlerData}; -use crate::trampoline::Trampoline; -use std::cell::Cell; -use std::ffi::c_void; -use std::ptr::{self, NonNull}; -use wasmer_runtime_core::typed_func::WasmTrapInfo; -use wasmer_runtime_core::vm::Ctx; -use wasmer_runtime_core::vm::Func; +use crate::{ + relocation::{TrapCode, TrapData}, + signal::{CallProtError, HandlerData}, +}; +use std::{ + cell::Cell, + ffi::c_void, + ptr::{self, NonNull}, +}; +use wasmer_runtime_core::{ + typed_func::{Trampoline, WasmTrapInfo}, + vm::{Ctx, Func}, +}; use wasmer_win_exception_handler::CallProtectedData; pub use wasmer_win_exception_handler::_call_protected; -use winapi::shared::minwindef::DWORD; -use winapi::um::minwinbase::{ - EXCEPTION_ACCESS_VIOLATION, EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_BREAKPOINT, - EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO, - EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW, - EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_GUARD_PAGE, - EXCEPTION_ILLEGAL_INSTRUCTION, EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, - EXCEPTION_INVALID_HANDLE, EXCEPTION_IN_PAGE_ERROR, EXCEPTION_NONCONTINUABLE_EXCEPTION, - EXCEPTION_POSSIBLE_DEADLOCK, EXCEPTION_PRIV_INSTRUCTION, EXCEPTION_SINGLE_STEP, - EXCEPTION_STACK_OVERFLOW, +use winapi::{ + shared::minwindef::DWORD, + um::minwinbase::{ + EXCEPTION_ACCESS_VIOLATION, EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_BREAKPOINT, + EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_FLT_DENORMAL_OPERAND, + EXCEPTION_FLT_DIVIDE_BY_ZERO, EXCEPTION_FLT_INEXACT_RESULT, + EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW, EXCEPTION_FLT_STACK_CHECK, + EXCEPTION_FLT_UNDERFLOW, EXCEPTION_GUARD_PAGE, EXCEPTION_ILLEGAL_INSTRUCTION, + EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_INVALID_HANDLE, + EXCEPTION_IN_PAGE_ERROR, EXCEPTION_NONCONTINUABLE_EXCEPTION, EXCEPTION_POSSIBLE_DEADLOCK, + EXCEPTION_PRIV_INSTRUCTION, EXCEPTION_SINGLE_STEP, EXCEPTION_STACK_OVERFLOW, + }, }; thread_local! { @@ -110,5 +116,5 @@ pub fn call_protected( pub unsafe fn trigger_trap() -> ! { // TODO - unimplemented!(); + unimplemented!("windows::trigger_trap"); } diff --git a/lib/clif-backend/src/trampoline.rs b/lib/clif-backend/src/trampoline.rs index a6fc6572b..fcd1ff83d 100644 --- a/lib/clif-backend/src/trampoline.rs +++ b/lib/clif-backend/src/trampoline.rs @@ -1,18 +1,16 @@ -use crate::cache::TrampolineCache; -use crate::resolver::NoopStackmapSink; +use crate::{cache::TrampolineCache, resolver::NoopStackmapSink}; use cranelift_codegen::{ binemit::{NullTrapSink, Reloc, RelocSink}, cursor::{Cursor, FuncCursor}, ir::{self, InstBuilder}, isa, Context, }; -use std::collections::HashMap; -use std::{iter, mem, ptr::NonNull}; +use std::{collections::HashMap, iter, mem}; use wasmer_runtime_core::{ backend::sys::{Memory, Protect}, module::{ExportIndex, ModuleInfo}, + typed_func::Trampoline, types::{FuncSig, SigIndex, Type}, - vm, }; struct NullRelocSink {} @@ -22,14 +20,12 @@ impl RelocSink for NullRelocSink { fn reloc_external(&mut self, _: u32, _: Reloc, _: &ir::ExternalName, _: i64) {} fn reloc_constant(&mut self, _: u32, _: Reloc, _: u32) { - unimplemented!() + unimplemented!("RelocSink::reloc_constant") } fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {} } -pub type Trampoline = unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64); - pub struct Trampolines { memory: Memory, offsets: HashMap, diff --git a/lib/dev-utils/Cargo.toml b/lib/dev-utils/Cargo.toml index bb6957b3a..3bb7c6f4f 100644 --- a/lib/dev-utils/Cargo.toml +++ b/lib/dev-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-dev-utils" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime core library" license = "MIT" authors = ["The Wasmer Engineering Team "] diff --git a/lib/emscripten-tests/Cargo.toml b/lib/emscripten-tests/Cargo.toml index 53bf8d2c2..8f2725f57 100644 --- a/lib/emscripten-tests/Cargo.toml +++ b/lib/emscripten-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten-tests" -version = "0.8.0" +version = "0.9.0" description = "Tests for our Emscripten implementation" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,15 +9,15 @@ publish = false build = "build/mod.rs" [dependencies] -wasmer-emscripten = { path = "../emscripten", version = "0.8.0" } -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.8.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.8.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } +wasmer-emscripten = { path = "../emscripten", version = "0.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.9.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } [dev-dependencies] wabt = "0.9.1" -wasmer-dev-utils = { path = "../dev-utils", version = "0.8.0"} +wasmer-dev-utils = { path = "../dev-utils", version = "0.9.0"} [build-dependencies] glob = "0.3" diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index e55fb221a..f51ee1a72 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime emscripten implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -12,10 +12,10 @@ byteorder = "1.3" lazy_static = "1.4" libc = "0.2.60" time = "0.1" -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } [target.'cfg(windows)'.dependencies] -rand = "0.7" +getrandom = "0.1" [features] debug = ["wasmer-runtime-core/debug"] diff --git a/lib/emscripten/src/exception.rs b/lib/emscripten/src/exception.rs index 09f04a798..09ae286f8 100644 --- a/lib/emscripten/src/exception.rs +++ b/lib/emscripten/src/exception.rs @@ -10,22 +10,22 @@ pub fn ___cxa_allocate_exception(ctx: &mut Ctx, size: u32) -> u32 { pub fn ___cxa_current_primary_exception(_ctx: &mut Ctx) -> u32 { debug!("emscripten::___cxa_current_primary_exception"); - unimplemented!() + unimplemented!("emscripten::___cxa_current_primary_exception") } pub fn ___cxa_decrement_exception_refcount(_ctx: &mut Ctx, _a: u32) { debug!("emscripten::___cxa_decrement_exception_refcount({})", _a); - unimplemented!() + unimplemented!("emscripten::___cxa_decrement_exception_refcount({})", _a) } pub fn ___cxa_increment_exception_refcount(_ctx: &mut Ctx, _a: u32) { debug!("emscripten::___cxa_increment_exception_refcount({})", _a); - unimplemented!() + unimplemented!("emscripten::___cxa_increment_exception_refcount({})", _a) } pub fn ___cxa_rethrow_primary_exception(_ctx: &mut Ctx, _a: u32) { debug!("emscripten::___cxa_rethrow_primary_exception({})", _a); - unimplemented!() + unimplemented!("emscripten::___cxa_rethrow_primary_exception({})", _a) } /// emscripten: ___cxa_throw diff --git a/lib/emscripten/src/io/mod.rs b/lib/emscripten/src/io/mod.rs index 6666cd5af..bad5935fe 100644 --- a/lib/emscripten/src/io/mod.rs +++ b/lib/emscripten/src/io/mod.rs @@ -15,13 +15,13 @@ use wasmer_runtime_core::vm::Ctx; /// getprotobyname pub fn getprotobyname(_ctx: &mut Ctx, _name_ptr: i32) -> i32 { debug!("emscripten::getprotobyname"); - unimplemented!() + unimplemented!("emscripten::getprotobyname") } /// getprotobynumber pub fn getprotobynumber(_ctx: &mut Ctx, _one: i32) -> i32 { debug!("emscripten::getprotobynumber"); - unimplemented!() + unimplemented!("emscripten::getprotobynumber") } /// sigdelset @@ -53,11 +53,11 @@ pub fn sigfillset(ctx: &mut Ctx, set: i32) -> i32 { /// tzset pub fn tzset(_ctx: &mut Ctx) { debug!("emscripten::tzset - stub"); - //unimplemented!() + //unimplemented!("emscripten::tzset - stub") } /// strptime pub fn strptime(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 { debug!("emscripten::strptime"); - unimplemented!() + unimplemented!("emscripten::strptime") } diff --git a/lib/emscripten/src/io/windows.rs b/lib/emscripten/src/io/windows.rs index a3c6f70aa..a7d6dc60b 100644 --- a/lib/emscripten/src/io/windows.rs +++ b/lib/emscripten/src/io/windows.rs @@ -36,11 +36,11 @@ pub fn printf(_ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 { /// chroot pub fn chroot(_ctx: &mut Ctx, _name_ptr: i32) -> i32 { debug!("emscripten::chroot"); - unimplemented!() + unimplemented!("emscripten::chroot") } /// getpwuid pub fn getpwuid(_ctx: &mut Ctx, _uid: i32) -> i32 { debug!("emscripten::getpwuid"); - unimplemented!() + unimplemented!("emscripten::getpwuid") } diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index efcff0a5e..cb015af3a 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -259,7 +259,7 @@ pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in ftruncate64(_fd, _length) } #[cfg(target_os = "macos")] - unimplemented!() + unimplemented!("emscripten::___syscall194 (ftruncate64) {}", _which) } /// lchown @@ -1111,6 +1111,6 @@ pub fn ___syscall324(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in } #[cfg(target_os = "macos")] { - unimplemented!() + unimplemented!("emscripten::___syscall324 (fallocate) {}", _which) } } diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index f6a867356..b5ed6cc83 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -2,7 +2,6 @@ use crate::utils::{copy_cstr_into_wasm, get_cstr_path}; use crate::varargs::VarArgs; use libc::mkdir; use libc::open; -use rand::Rng; use std::env; use std::ffi::CString; use std::fs::File; @@ -39,7 +38,8 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { let ptr = tmp_dir_c_str.as_ptr() as *const i8; let mut urandom_file = File::create(tmp_dir).unwrap(); // create some random bytes and put them into the file - let random_bytes = rand::thread_rng().gen::<[u8; 32]>(); + let mut random_bytes = [0u8; 32]; + getrandom::getrandom(&mut random_bytes).unwrap(); let _ = urandom_file.write_all(&random_bytes).unwrap(); // put the file path string into wasm memory let urandom_file_offset = unsafe { copy_cstr_into_wasm(ctx, ptr) }; @@ -66,13 +66,13 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { /// link pub fn ___syscall9(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall9 (link) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall9 (link) {}", _which); } /// ftruncate64 pub fn ___syscall194(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall194 - stub"); - unimplemented!() + unimplemented!("emscripten::___syscall194 - stub") } // chown @@ -86,13 +86,13 @@ pub fn ___syscall212(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i /// access pub fn ___syscall33(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall33 (access) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall33 (access) {}", _which); } /// nice pub fn ___syscall34(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall34 (nice) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall34 (nice) {}", _which); } // mkdir @@ -113,19 +113,19 @@ pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int /// dup pub fn ___syscall41(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall41 (dup) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall41 (dup) {}", _which); } /// getrusage pub fn ___syscall77(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall77 (getrusage) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall77 (getrusage) {}", _which); } /// symlink pub fn ___syscall83(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall83 (symlink) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall83 (symlink) {}", _which); } /// readlink @@ -143,38 +143,38 @@ pub fn ___syscall132(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_ /// lchown pub fn ___syscall198(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall198 (lchown) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall198 (lchown) {}", _which); } /// getgid32 pub fn ___syscall200(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall200 (getgid32)"); - unimplemented!(); + unimplemented!("emscripten::___syscall200 (getgid32)"); } // geteuid32 pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall201 (geteuid32)"); - unimplemented!(); + unimplemented!("emscripten::___syscall201 (geteuid32)"); } // getegid32 pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { // gid_t debug!("emscripten::___syscall202 (getegid32)"); - unimplemented!(); + unimplemented!("emscripten::___syscall202 (getegid32)"); } /// getgroups pub fn ___syscall205(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall205 (getgroups) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall205 (getgroups) {}", _which); } /// madvise pub fn ___syscall219(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall212 (chown) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall212 (chown) {}", _which); } /// dup3 @@ -194,7 +194,7 @@ pub fn ___syscall54(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_in /// fchmod pub fn ___syscall94(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall118 (fchmod) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall118 (fchmod) {}", _which); } // socketcall @@ -209,7 +209,7 @@ pub fn ___syscall102(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i /// fsync pub fn ___syscall118(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall118 (fsync) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall118 (fsync) {}", _which); } // pread @@ -247,7 +247,7 @@ pub fn ___syscall142(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i /// fdatasync pub fn ___syscall148(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall148 (fdatasync) {}", _which); - unimplemented!(); + unimplemented!("emscripten::___syscall148 (fdatasync) {}", _which); } // setpgid @@ -300,11 +300,11 @@ pub fn ___syscall221(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_ /// fchown pub fn ___syscall207(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall207 (fchown) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall207 (fchown) {}", _which) } /// fallocate pub fn ___syscall324(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall324 (fallocate) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall324 (fallocate) {}", _which) } diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 1cc15ec89..4cd3e2479 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -1,17 +1,16 @@ [package] name = "wasmer-llvm-backend" -version = "0.8.0" +version = "0.9.0" authors = ["The Wasmer Engineering Team "] edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } wasmparser = "0.39.1" smallvec = "0.6" goblin = "0.0.24" libc = "0.2.60" -capstone = { version = "0.6", optional = true } byteorder = "1" [dependencies.inkwell] @@ -38,4 +37,3 @@ wabt = "0.9.1" [features] debug = ["wasmer-runtime-core/debug"] -disasm = ["capstone"] diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 682bd7278..a5d262035 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -1,21 +1,24 @@ use super::stackmap::StackmapRegistry; -use crate::intrinsics::Intrinsics; -use crate::structs::{Callbacks, LLVMModule, LLVMResult, MemProtect}; +use crate::{ + intrinsics::Intrinsics, + structs::{Callbacks, LLVMModule, LLVMResult, MemProtect}, +}; use inkwell::{ memory_buffer::MemoryBuffer, module::Module, - targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine}, - OptimizationLevel, + targets::{FileType, TargetMachine}, }; use libc::c_char; use std::{ any::Any, + cell::RefCell, ffi::{c_void, CString}, fs::File, io::Write, mem, ops::Deref, ptr::{self, NonNull}, + rc::Rc, slice, str, sync::{Arc, Once}, }; @@ -28,7 +31,7 @@ use wasmer_runtime_core::{ module::ModuleInfo, state::ModuleStateMap, structures::TypedIndex, - typed_func::{Wasm, WasmTrapInfo}, + typed_func::{Trampoline, Wasm, WasmTrapInfo}, types::{LocalFuncIndex, SigIndex}, vm, vmcalls, }; @@ -58,7 +61,7 @@ extern "C" { #[allow(improper_ctypes)] fn invoke_trampoline( - trampoline: unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64), + trampoline: Trampoline, vmctx_ptr: *mut vm::Ctx, func_ptr: NonNull, params: *const u64, @@ -168,34 +171,14 @@ pub struct LLVMBackend { impl LLVMBackend { pub fn new( - module: Module, + module: Rc>, _intrinsics: Intrinsics, _stackmaps: &StackmapRegistry, _module_info: &ModuleInfo, + target_machine: &TargetMachine, ) -> (Self, LLVMCache) { - Target::initialize_x86(&InitializationConfig { - asm_parser: true, - asm_printer: true, - base: true, - disassembler: true, - info: true, - machine_code: true, - }); - let triple = TargetMachine::get_default_triple().to_string(); - let target = Target::from_triple(&triple).unwrap(); - let target_machine = target - .create_target_machine( - &triple, - &TargetMachine::get_host_cpu_name().to_string(), - &TargetMachine::get_host_cpu_features().to_string(), - OptimizationLevel::Aggressive, - RelocMode::Static, - CodeModel::Large, - ) - .unwrap(); - let memory_buffer = target_machine - .write_to_memory_buffer(&module, FileType::Object) + .write_to_memory_buffer(&module.borrow_mut(), FileType::Object) .unwrap(); let mem_buf_slice = memory_buffer.as_slice(); @@ -408,12 +391,7 @@ impl RunnableModule for LLVMBackend { } fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { - let trampoline: unsafe extern "C" fn( - *mut vm::Ctx, - NonNull, - *const u64, - *mut u64, - ) = unsafe { + let trampoline: Trampoline = unsafe { let name = if cfg!(target_os = "macos") { format!("_trmp{}", sig_index.index()) } else { @@ -477,33 +455,3 @@ impl CacheGen for LLVMCache { Ok(([].as_ref().into(), memory)) } } - -#[cfg(feature = "disasm")] -unsafe fn disass_ptr(ptr: *const u8, size: usize, inst_count: usize) { - use capstone::arch::BuildsCapstone; - let mut cs = capstone::Capstone::new() // Call builder-pattern - .x86() // X86 architecture - .mode(capstone::arch::x86::ArchMode::Mode64) // 64-bit mode - .detail(true) // Generate extra instruction details - .build() - .expect("Failed to create Capstone object"); - - // Get disassembled instructions - let insns = cs - .disasm_count( - std::slice::from_raw_parts(ptr, size), - ptr as u64, - inst_count, - ) - .expect("Failed to disassemble"); - - println!("count = {}", insns.len()); - for insn in insns.iter() { - println!( - "0x{:x}: {:6} {}", - insn.address(), - insn.mnemonic().unwrap_or(""), - insn.op_str().unwrap_or("") - ); - } -} diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 8ac76fe26..7b5f2d1a2 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -1,21 +1,32 @@ +use crate::{ + backend::LLVMBackend, + intrinsics::{tbaa_label, CtxType, GlobalCache, Intrinsics, MemoryCache}, + read_info::{blocktype_to_type, type_to_type}, + stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic}, + state::{ControlFrame, ExtraInfo, IfElseState, State}, + trampolines::generate_trampolines, +}; use inkwell::{ builder::Builder, context::Context, module::{Linkage, Module}, passes::PassManager, + targets::{CodeModel, InitializationConfig, RelocMode, Target, TargetMachine}, types::{BasicType, BasicTypeEnum, FunctionType, PointerType, VectorType}, values::{ BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PhiValue, PointerValue, VectorValue, }, - AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate, + AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate, OptimizationLevel, }; use smallvec::SmallVec; -use std::cell::RefCell; -use std::rc::Rc; -use std::sync::{Arc, RwLock}; +use std::{ + cell::RefCell, + rc::Rc, + sync::{Arc, RwLock}, +}; use wasmer_runtime_core::{ - backend::{Backend, CacheGen, Token}, + backend::{Backend, CacheGen, CompilerConfig, Token}, cache::{Artifact, Error as CacheError}, codegen::*, memory::MemoryType, @@ -27,13 +38,6 @@ use wasmer_runtime_core::{ }; use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType}; -use crate::backend::LLVMBackend; -use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; -use crate::read_info::{blocktype_to_type, type_to_type}; -use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic}; -use crate::state::{ControlFrame, IfElseState, State}; -use crate::trampolines::generate_trampolines; - fn func_sig_to_llvm( context: &Context, intrinsics: &Intrinsics, @@ -376,6 +380,138 @@ fn trap_if_zero( builder.position_at_end(&shouldnt_trap_block); } +fn v128_into_int_vec( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, + int_vec_ty: VectorType, +) -> VectorValue { + let value = match info { + ExtraInfo::None => value, + ExtraInfo::PendingF32NaN => { + let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } + ExtraInfo::PendingF64NaN => { + let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } + }; + builder + .build_bitcast(value, int_vec_ty, "") + .into_vector_value() +} + +fn v128_into_i8x16( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i8x16_ty) +} + +fn v128_into_i16x8( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i16x8_ty) +} + +fn v128_into_i32x4( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i32x4_ty) +} + +fn v128_into_i64x2( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i64x2_ty) +} + +// If the value is pending a 64-bit canonicalization, do it now. +// Return a f32x4 vector. +fn v128_into_f32x4( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + let value = if info == ExtraInfo::PendingF64NaN { + let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } else { + value + }; + builder + .build_bitcast(value, intrinsics.f32x4_ty, "") + .into_vector_value() +} + +// If the value is pending a 32-bit canonicalization, do it now. +// Return a f64x2 vector. +fn v128_into_f64x2( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + let value = if info == ExtraInfo::PendingF32NaN { + let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } else { + value + }; + builder + .build_bitcast(value, intrinsics.f64x2_ty, "") + .into_vector_value() +} + +fn apply_pending_canonicalization( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> BasicValueEnum { + match info { + ExtraInfo::None => value, + ExtraInfo::PendingF32NaN => { + if value.get_type().is_vector_type() + || value.get_type() == intrinsics.i128_ty.as_basic_type_enum() + { + let ty = value.get_type(); + let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); + let value = canonicalize_nans(builder, intrinsics, value); + builder.build_bitcast(value, ty, "") + } else { + canonicalize_nans(builder, intrinsics, value) + } + } + ExtraInfo::PendingF64NaN => { + if value.get_type().is_vector_type() + || value.get_type() == intrinsics.i128_ty.as_basic_type_enum() + { + let ty = value.get_type(); + let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); + let value = canonicalize_nans(builder, intrinsics, value); + builder.build_bitcast(value, ty, "") + } else { + canonicalize_nans(builder, intrinsics, value) + } + } + } +} + // Replaces any NaN with the canonical QNaN, otherwise leaves the value alone. fn canonicalize_nans( builder: &Builder, @@ -419,6 +555,7 @@ fn resolve_memory_ptr( builder: &Builder, intrinsics: &Intrinsics, context: &Context, + module: Rc>, function: &FunctionValue, state: &mut State, ctx: &mut CtxType, @@ -426,51 +563,98 @@ fn resolve_memory_ptr( ptr_ty: PointerType, value_size: usize, ) -> Result { - // Ignore alignment hint for the time being. - let imm_offset = intrinsics.i64_ty.const_int(memarg.offset as u64, false); - let value_size_v = intrinsics.i64_ty.const_int(value_size as u64, false); - let var_offset_i32 = state.pop1()?.into_int_value(); - let var_offset = - builder.build_int_z_extend(var_offset_i32, intrinsics.i64_ty, &state.var_name()); - let effective_offset = builder.build_int_add(var_offset, imm_offset, &state.var_name()); - let end_offset = builder.build_int_add(effective_offset, value_size_v, &state.var_name()); - let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics); - - let mem_base_int = match memory_cache { + // Look up the memory base (as pointer) and bounds (as unsigned integer). + let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics, module.clone()); + let (mem_base, mem_bound, minimum, _maximum) = match memory_cache { MemoryCache::Dynamic { ptr_to_base_ptr, ptr_to_bounds, + minimum, + maximum, } => { let base = builder .build_load(ptr_to_base_ptr, "base") .into_pointer_value(); let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value(); + tbaa_label( + module.clone(), + intrinsics, + "dynamic_memory_base", + base.as_instruction_value().unwrap(), + Some(0), + ); + tbaa_label( + module.clone(), + intrinsics, + "dynamic_memory_bounds", + bounds.as_instruction_value().unwrap(), + Some(0), + ); + (base, bounds, minimum, maximum) + } + MemoryCache::Static { + base_ptr, + bounds, + minimum, + maximum, + } => (base_ptr, bounds, minimum, maximum), + }; + let mem_base = builder + .build_bitcast(mem_base, intrinsics.i8_ptr_ty, &state.var_name()) + .into_pointer_value(); - let base_as_int = builder.build_ptr_to_int(base, intrinsics.i64_ty, "base_as_int"); + // Compute the offset over the memory_base. + let imm_offset = intrinsics.i64_ty.const_int(memarg.offset as u64, false); + let var_offset_i32 = state.pop1()?.into_int_value(); + let var_offset = + builder.build_int_z_extend(var_offset_i32, intrinsics.i64_ty, &state.var_name()); + let effective_offset = builder.build_int_add(var_offset, imm_offset, &state.var_name()); - let base_in_bounds_1 = builder.build_int_compare( + if let MemoryCache::Dynamic { .. } = memory_cache { + // If the memory is dynamic, do a bounds check. For static we rely on + // the size being a multiple of the page size and hitting a guard page. + let value_size_v = intrinsics.i64_ty.const_int(value_size as u64, false); + let ptr_in_bounds = if effective_offset.is_const() { + let load_offset_end = effective_offset.const_add(value_size_v); + let ptr_in_bounds = load_offset_end.const_int_compare( IntPredicate::ULE, - end_offset, - bounds, - "base_in_bounds_1", + intrinsics.i64_ty.const_int(minimum.bytes().0 as u64, false), ); - let base_in_bounds_2 = builder.build_int_compare( - IntPredicate::ULT, - effective_offset, - end_offset, - "base_in_bounds_2", - ); - let base_in_bounds = - builder.build_and(base_in_bounds_1, base_in_bounds_2, "base_in_bounds"); + if ptr_in_bounds.get_zero_extended_constant() == Some(1) { + Some(ptr_in_bounds) + } else { + None + } + } else { + None + } + .unwrap_or_else(|| { + let load_offset_end = + builder.build_int_add(effective_offset, value_size_v, &state.var_name()); - let base_in_bounds = builder + builder.build_int_compare( + IntPredicate::ULE, + load_offset_end, + mem_bound, + &state.var_name(), + ) + }); + if !ptr_in_bounds.is_constant_int() + || ptr_in_bounds.get_zero_extended_constant().unwrap() != 1 + { + // LLVM may have folded this into 'i1 true' in which case we know + // the pointer is in bounds. LLVM may also have folded it into a + // constant expression, not known to be either true or false yet. + // If it's false, unknown-but-constant, or not-a-constant, emit a + // runtime bounds check. LLVM may yet succeed at optimizing it away. + let ptr_in_bounds = builder .build_call( intrinsics.expect_i1, &[ - base_in_bounds.as_basic_value_enum(), + ptr_in_bounds.as_basic_value_enum(), intrinsics.i1_ty.const_int(1, false).as_basic_value_enum(), ], - "base_in_bounds_expect", + "ptr_in_bounds_expect", ) .try_as_basic_value() .left() @@ -481,7 +665,7 @@ fn resolve_memory_ptr( context.append_basic_block(function, "in_bounds_continue_block"); let not_in_bounds_block = context.append_basic_block(function, "not_in_bounds_block"); builder.build_conditional_branch( - base_in_bounds, + ptr_in_bounds, &in_bounds_continue_block, ¬_in_bounds_block, ); @@ -493,18 +677,13 @@ fn resolve_memory_ptr( ); builder.build_unreachable(); builder.position_at_end(&in_bounds_continue_block); - - base_as_int } - MemoryCache::Static { - base_ptr, - bounds: _, - } => builder.build_ptr_to_int(base_ptr, intrinsics.i64_ty, "base_as_int"), - }; + } - let effective_address_int = - builder.build_int_add(mem_base_int, effective_offset, &state.var_name()); - Ok(builder.build_int_to_ptr(effective_address_int, ptr_ty, &state.var_name())) + let ptr = unsafe { builder.build_gep(mem_base, &[effective_offset], &state.var_name()) }; + Ok(builder + .build_bitcast(ptr, ptr_ty, &state.var_name()) + .into_pointer_value()) } fn emit_stack_map( @@ -538,7 +717,7 @@ fn emit_stack_map( params.extend_from_slice(&locals); value_semantics.extend((0..locals.len()).map(ValueSemantic::WasmLocal)); - params.extend_from_slice(&state.stack); + params.extend(state.stack.iter().map(|x| x.0)); value_semantics.extend((0..state.stack.len()).map(ValueSemantic::WasmStack)); // FIXME: Information needed for Abstract -> Runtime state transform is not fully preserved @@ -674,13 +853,16 @@ pub struct LLVMModuleCodeGenerator { function_signatures: Option>>, func_import_count: usize, personality_func: FunctionValue, - module: Module, + module: Rc>, stackmaps: Rc>, + track_state: bool, + target_machine: TargetMachine, } pub struct LLVMFunctionCodeGenerator { context: Option, builder: Option, + alloca_builder: Option, intrinsics: Option, state: State, function: FunctionValue, @@ -693,6 +875,8 @@ pub struct LLVMFunctionCodeGenerator { stackmaps: Rc>, index: usize, opcode_offset: usize, + track_state: bool, + module: Rc>, } impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { @@ -704,12 +888,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Ok(()) } - fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> { + fn feed_local(&mut self, ty: WpType, count: usize) -> Result<(), CodegenError> { let param_len = self.num_params; - let mut local_idx = 0; - // let (count, ty) = local?; - let count = n; let wasmer_ty = type_to_type(ty)?; let intrinsics = self.intrinsics.as_ref().unwrap(); @@ -724,14 +905,22 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { }; let builder = self.builder.as_ref().unwrap(); + let alloca_builder = self.alloca_builder.as_ref().unwrap(); - for _ in 0..count { - let alloca = builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); - + for local_idx in 0..count { + let alloca = + alloca_builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); builder.build_store(alloca, default_value); - + if local_idx == 0 { + alloca_builder.position_before( + &alloca + .as_instruction() + .unwrap() + .get_next_instruction() + .unwrap(), + ); + } self.locals.push(alloca); - local_idx += 1; } Ok(()) } @@ -768,27 +957,29 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let builder = self.builder.as_ref().unwrap(); let intrinsics = self.intrinsics.as_ref().unwrap(); - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &module_info, - &intrinsics, - &builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::FunctionHeader, - &self.locals, - &state, - self.ctx.as_mut().unwrap(), - ::std::usize::MAX, - ); - finalize_opcode_stack_map( - &intrinsics, - &builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::FunctionHeader, - ::std::usize::MAX, - ); + if self.track_state { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &module_info, + &intrinsics, + &builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::FunctionHeader, + &self.locals, + &state, + self.ctx.as_mut().unwrap(), + ::std::usize::MAX, + ); + finalize_opcode_stack_map( + &intrinsics, + &builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::FunctionHeader, + ::std::usize::MAX, + ); + } } Ok(()) @@ -830,17 +1021,33 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { InternalEvent::GetInternal(idx) => { if state.reachable { let idx = idx as usize; - let field_ptr = ctx.internal_field(idx, intrinsics, builder); + let field_ptr = + ctx.internal_field(idx, intrinsics, self.module.clone(), builder); let result = builder.build_load(field_ptr, "get_internal"); + tbaa_label( + self.module.clone(), + intrinsics, + "internal", + result.as_instruction_value().unwrap(), + Some(idx as u32), + ); state.push1(result); } } InternalEvent::SetInternal(idx) => { if state.reachable { let idx = idx as usize; - let field_ptr = ctx.internal_field(idx, intrinsics, builder); + let field_ptr = + ctx.internal_field(idx, intrinsics, self.module.clone(), builder); let v = state.pop1()?; - builder.build_store(field_ptr, v); + let store = builder.build_store(field_ptr, v); + tbaa_label( + self.module.clone(), + intrinsics, + "internal", + store, + Some(idx as u32), + ); } } } @@ -918,32 +1125,35 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.position_at_end(&loop_body); - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &info, - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Loop, - &self.locals, - state, - ctx, - offset, - ); - let signal_mem = ctx.signal_mem(); - let iv = builder - .build_store(signal_mem, context.i8_type().const_int(0 as u64, false)); - iv.set_volatile(true); - finalize_opcode_stack_map( - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Loop, - offset, - ); + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &info, + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Loop, + &self.locals, + state, + ctx, + offset, + ); + let signal_mem = ctx.signal_mem(); + let iv = builder + .build_store(signal_mem, context.i8_type().const_int(0 as u64, false)); + // Any 'store' can be made volatile. + iv.set_volatile(true).unwrap(); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Loop, + offset, + ); + } } state.push_loop(loop_body, loop_next, phis); @@ -962,13 +1172,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { frame.phis().len() }; - let values = state.peekn(value_len)?; + let values = state.peekn_extra(value_len)?; + let values = values.iter().map(|(v, info)| { + apply_pending_canonicalization(builder, intrinsics, *v, *info) + }); // For each result of the block we're branching to, // pop a value off the value stack and load it into // the corresponding phi. - for (phi, value) in frame.phis().iter().zip(values.iter()) { - phi.add_incoming(&[(value, ¤t_block)]); + for (phi, value) in frame.phis().iter().zip(values) { + phi.add_incoming(&[(&value, ¤t_block)]); } builder.build_unconditional_branch(frame.br_dest()); @@ -991,10 +1204,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { frame.phis().len() }; - let param_stack = state.peekn(value_len)?; + let param_stack = state.peekn_extra(value_len)?; + let param_stack = param_stack.iter().map(|(v, info)| { + apply_pending_canonicalization(builder, intrinsics, *v, *info) + }); - for (phi, value) in frame.phis().iter().zip(param_stack.iter()) { - phi.add_incoming(&[(value, ¤t_block)]); + for (phi, value) in frame.phis().iter().zip(param_stack) { + phi.add_incoming(&[(&value, ¤t_block)]); } let else_block = context.append_basic_block(&function, "else"); @@ -1021,7 +1237,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let default_frame = state.frame_at_depth(default_depth)?; let args = if default_frame.is_loop() { - &[] + Vec::new() } else { let res_len = default_frame.phis().len(); state.peekn(res_len)? @@ -1100,16 +1316,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::Else => { if state.reachable { let frame = state.frame_at_depth(0)?; - builder.build_unconditional_branch(frame.code_after()); let current_block = builder.get_insert_block().ok_or(BinaryReaderError { message: "not currently in a block", offset: -1isize as usize, })?; for phi in frame.phis().to_vec().iter().rev() { - let value = state.pop1()?; + let (value, info) = state.pop1_extra()?; + let value = + apply_pending_canonicalization(builder, intrinsics, value, info); phi.add_incoming(&[(&value, ¤t_block)]) } + let frame = state.frame_at_depth(0)?; + builder.build_unconditional_branch(frame.code_after()); } let (if_else_block, if_else_state) = if let ControlFrame::IfElse { @@ -1137,12 +1356,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { })?; if state.reachable { - builder.build_unconditional_branch(frame.code_after()); - for phi in frame.phis().iter().rev() { - let value = state.pop1()?; + let (value, info) = state.pop1_extra()?; + let value = + apply_pending_canonicalization(builder, intrinsics, value, info); phi.add_incoming(&[(&value, ¤t_block)]); } + + builder.build_unconditional_branch(frame.code_after()); } if let ControlFrame::IfElse { @@ -1196,10 +1417,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_unconditional_branch(frame.br_dest()); - let phis = frame.phis().to_vec(); - - for phi in phis.iter() { - let arg = state.pop1()?; + let frame = state.outermost_frame()?; + for phi in frame.phis().to_vec().iter() { + let (arg, info) = state.pop1_extra()?; + let arg = apply_pending_canonicalization(builder, intrinsics, arg, info); phi.add_incoming(&[(&arg, ¤t_block)]); } @@ -1208,34 +1429,36 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::Unreachable => { // Emit an unreachable instruction. - // If llvm cannot prove that this is never touched, + // If llvm cannot prove that this is never reached, // it will emit a `ud2` instruction on x86_64 arches. // Comment out this `if` block to allow spectests to pass. // TODO: fix this if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &info, - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Trappable, - &self.locals, - state, - ctx, - offset, - ); - builder.build_call(intrinsics.trap, &[], "trap"); - finalize_opcode_stack_map( - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Trappable, - offset, - ); + if self.track_state { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &info, + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Trappable, + &self.locals, + state, + ctx, + offset, + ); + builder.build_call(intrinsics.trap, &[], "trap"); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Trappable, + offset, + ); + } } builder.build_call( @@ -1339,7 +1562,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Splat => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = splat_vector( builder, intrinsics, @@ -1348,10 +1571,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + // The spec is unclear, we interpret splat as preserving NaN + // payload bits. + state.push1_extra(res, i); } Operator::F64x2Splat => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = splat_vector( builder, intrinsics, @@ -1360,46 +1585,86 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + // The spec is unclear, we interpret splat as preserving NaN + // payload bits. + state.push1_extra(res, i); } // Operate on locals. Operator::GetLocal { local_index } => { let pointer_value = locals[local_index as usize]; let v = builder.build_load(pointer_value, &state.var_name()); + tbaa_label( + self.module.clone(), + intrinsics, + "local", + v.as_instruction_value().unwrap(), + Some(local_index), + ); state.push1(v); } Operator::SetLocal { local_index } => { let pointer_value = locals[local_index as usize]; - let v = state.pop1()?; - builder.build_store(pointer_value, v); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let store = builder.build_store(pointer_value, v); + tbaa_label( + self.module.clone(), + intrinsics, + "local", + store, + Some(local_index), + ); } Operator::TeeLocal { local_index } => { let pointer_value = locals[local_index as usize]; - let v = state.peek1()?; - builder.build_store(pointer_value, v); + let (v, i) = state.peek1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); + let store = builder.build_store(pointer_value, v); + tbaa_label( + self.module.clone(), + intrinsics, + "local", + store, + Some(local_index), + ); } Operator::GetGlobal { global_index } => { let index = GlobalIndex::new(global_index as usize); - let global_cache = ctx.global_cache(index, intrinsics); + let global_cache = ctx.global_cache(index, intrinsics, self.module.clone()); match global_cache { GlobalCache::Const { value } => { state.push1(value); } GlobalCache::Mut { ptr_to_value } => { let value = builder.build_load(ptr_to_value, "global_value"); + tbaa_label( + self.module.clone(), + intrinsics, + "global", + value.as_instruction_value().unwrap(), + Some(global_index), + ); state.push1(value); } } } Operator::SetGlobal { global_index } => { - let value = state.pop1()?; + let (value, info) = state.pop1_extra()?; + let value = apply_pending_canonicalization(builder, intrinsics, value, info); let index = GlobalIndex::new(global_index as usize); - let global_cache = ctx.global_cache(index, intrinsics); + let global_cache = ctx.global_cache(index, intrinsics, self.module.clone()); match global_cache { GlobalCache::Mut { ptr_to_value } => { - builder.build_store(ptr_to_value, value); + let store = builder.build_store(ptr_to_value, value); + tbaa_label( + self.module.clone(), + intrinsics, + "global", + store, + Some(global_index), + ); } GlobalCache::Const { value: _ } => { return Err(CodegenError { @@ -1431,52 +1696,71 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let params: Vec<_> = std::iter::once(ctx.basic()) .chain( state - .peekn(func_sig.params().len())? + .peekn_extra(func_sig.params().len())? .iter() .enumerate() - .map(|(i, &v)| match func_sig.params()[i] { + .map(|(i, (v, info))| match func_sig.params()[i] { Type::F32 => builder.build_bitcast( - v, + apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), intrinsics.i32_ty, &state.var_name(), ), Type::F64 => builder.build_bitcast( - v, + apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), intrinsics.i64_ty, &state.var_name(), ), - _ => v, + Type::V128 => apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), + _ => *v, }), ) .collect(); - let func_ptr = - ctx.local_func(local_func_index, llvm_sig, intrinsics, builder); + let func_ptr = ctx.local_func( + local_func_index, + llvm_sig, + intrinsics, + self.module.clone(), + builder, + ); (params, func_ptr) } LocalOrImport::Import(import_func_index) => { let (func_ptr_untyped, ctx_ptr) = - ctx.imported_func(import_func_index, intrinsics); + ctx.imported_func(import_func_index, intrinsics, self.module.clone()); let params: Vec<_> = std::iter::once(ctx_ptr.as_basic_value_enum()) .chain( state - .peekn(func_sig.params().len())? + .peekn_extra(func_sig.params().len())? .iter() .enumerate() - .map(|(i, &v)| match func_sig.params()[i] { + .map(|(i, (v, info))| match func_sig.params()[i] { Type::F32 => builder.build_bitcast( - v, + apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), intrinsics.i32_ty, &state.var_name(), ), Type::F64 => builder.build_bitcast( - v, + apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), intrinsics.i64_ty, &state.var_name(), ), - _ => v, + Type::V128 => apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), + _ => *v, }), ) .collect(); @@ -1494,32 +1778,36 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { }; state.popn(func_sig.params().len())?; - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &info, - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Call, - &self.locals, - state, - ctx, - offset, - ) + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &info, + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + &self.locals, + state, + ctx, + offset, + ) + } } let call_site = builder.build_call(func_ptr, ¶ms, &state.var_name()); - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - finalize_opcode_stack_map( - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Call, - offset, - ) + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + offset, + ) + } } if let Some(basic_value) = call_site.try_as_basic_value().left() { @@ -1549,8 +1837,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::CallIndirect { index, table_index } => { let sig_index = SigIndex::new(index as usize); let expected_dynamic_sigindex = ctx.dynamic_sigindex(sig_index, intrinsics); - let (table_base, table_bound) = - ctx.table(TableIndex::new(table_index as usize), intrinsics, builder); + let (table_base, table_bound) = ctx.table( + TableIndex::new(table_index as usize), + intrinsics, + self.module.clone(), + builder, + ); let func_index = state.pop1()?.into_int_value(); // We assume the table has the `anyfunc` element type. @@ -1681,16 +1973,23 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let wasmer_fn_sig = &info.signatures[sig_index]; let fn_ty = signatures[sig_index]; - let pushed_args = state.popn_save(wasmer_fn_sig.params().len())?; + let pushed_args = state.popn_save_extra(wasmer_fn_sig.params().len())?; let args: Vec<_> = std::iter::once(ctx_ptr) - .chain(pushed_args.into_iter().enumerate().map(|(i, v)| { + .chain(pushed_args.into_iter().enumerate().map(|(i, (v, info))| { match wasmer_fn_sig.params()[i] { - Type::F32 => { - builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()) - } - Type::F64 => { - builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()) + Type::F32 => builder.build_bitcast( + apply_pending_canonicalization(builder, intrinsics, v, info), + intrinsics.i32_ty, + &state.var_name(), + ), + Type::F64 => builder.build_bitcast( + apply_pending_canonicalization(builder, intrinsics, v, info), + intrinsics.i64_ty, + &state.var_name(), + ), + Type::V128 => { + apply_pending_canonicalization(builder, intrinsics, v, info) } _ => v, } @@ -1703,32 +2002,36 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { "typed_func_ptr", ); - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &info, - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Call, - &self.locals, - state, - ctx, - offset, - ) + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &info, + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + &self.locals, + state, + ctx, + offset, + ) + } } let call_site = builder.build_call(typed_func_ptr, &args, "indirect_call"); - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - finalize_opcode_stack_map( - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Call, - offset, - ) + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + offset, + ) + } } match wasmer_fn_sig.returns() { @@ -1765,59 +2068,41 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I64x2Add => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_i64x2(builder, intrinsics, v2, i2); let res = builder.build_int_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I8x16AddSaturateS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i8x16_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i8x16_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.sadd_sat_i8x16, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1827,10 +2112,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8AddSaturateS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i16x8_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i16x8_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.sadd_sat_i16x8, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1840,10 +2124,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16AddSaturateU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i8x16_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i8x16_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.uadd_sat_i8x16, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1853,10 +2136,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8AddSaturateU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i16x8_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i16x8_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.uadd_sat_i16x8, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1872,62 +2154,41 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I64x2Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_i64x2(builder, intrinsics, v2, i2); let res = builder.build_int_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I8x16SubSaturateS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i8x16_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i8x16_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.ssub_sat_i8x16, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1937,10 +2198,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8SubSaturateS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i16x8_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i16x8_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.ssub_sat_i16x8, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1950,10 +2210,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16SubSaturateU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i8x16_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i8x16_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.usub_sat_i8x16, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1963,10 +2222,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8SubSaturateU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i16x8_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i16x8_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.usub_sat_i16x8, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1982,40 +2240,25 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Mul => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Mul => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Mul => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); @@ -2093,25 +2336,34 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32And | Operator::I64And | Operator::V128And => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = builder.build_and(v1, v2, &state.var_name()); state.push1(res); } Operator::I32Or | Operator::I64Or | Operator::V128Or => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = builder.build_or(v1, v2, &state.var_name()); state.push1(res); } Operator::I32Xor | Operator::I64Xor | Operator::V128Xor => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = builder.build_xor(v1, v2, &state.var_name()); state.push1(res); } Operator::V128Bitselect => { - let (v1, v2, cond) = state.pop3()?; + let ((v1, i1), (v2, i2), (cond, cond_info)) = state.pop3_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); + let cond = apply_pending_canonicalization(builder, intrinsics, cond, cond_info); let v1 = builder .build_bitcast(v1, intrinsics.i1x128_ty, "") .into_vector_value(); @@ -2133,10 +2385,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Shl => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(7, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i8_ty, ""); @@ -2152,10 +2402,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8Shl => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(15, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i16_ty, ""); @@ -2171,10 +2419,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4Shl => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(31, false), ""); let v2 = splat_vector( @@ -2189,10 +2435,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2Shl => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(63, false), ""); let v2 = builder.build_int_z_extend(v2, intrinsics.i64_ty, ""); @@ -2215,10 +2459,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16ShrS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(7, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i8_ty, ""); @@ -2234,10 +2476,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ShrS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(15, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i16_ty, ""); @@ -2253,10 +2493,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ShrS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(31, false), ""); let v2 = splat_vector( @@ -2271,10 +2509,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2ShrS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(63, false), ""); let v2 = builder.build_int_z_extend(v2, intrinsics.i64_ty, ""); @@ -2296,10 +2532,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16ShrU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(7, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i8_ty, ""); @@ -2315,10 +2549,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ShrU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(15, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i16_ty, ""); @@ -2334,10 +2566,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ShrU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(31, false), ""); let v2 = splat_vector( @@ -2352,10 +2582,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2ShrU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(63, false), ""); let v2 = builder.build_int_z_extend(v2, intrinsics.i64_ty, ""); @@ -2420,14 +2648,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32Clz => { let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); + let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( intrinsics.ctlz_i32, - &[input, ensure_defined_zero], + &[input, is_zero_undef], &state.var_name(), ) .try_as_basic_value() @@ -2437,14 +2662,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I64Clz => { let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); + let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( intrinsics.ctlz_i64, - &[input, ensure_defined_zero], + &[input, is_zero_undef], &state.var_name(), ) .try_as_basic_value() @@ -2454,14 +2676,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32Ctz => { let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); + let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( intrinsics.cttz_i32, - &[input, ensure_defined_zero], + &[input, is_zero_undef], &state.var_name(), ) .try_as_basic_value() @@ -2471,14 +2690,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I64Ctz => { let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); + let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( intrinsics.cttz_i64, - &[input, ensure_defined_zero], + &[input, is_zero_undef], &state.var_name(), ) .try_as_basic_value() @@ -2531,125 +2747,117 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { * Floating-Point Arithmetic instructions. * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-arithmetic-instructions ***************************/ - Operator::F32Add | Operator::F64Add => { + Operator::F32Add => { let (v1, v2) = state.pop2()?; - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let res = builder.build_float_add(v1, v2, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); + } + Operator::F64Add => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_add(v1, v2, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64x2Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } - Operator::F32Sub | Operator::F64Sub => { + Operator::F32Sub => { let (v1, v2) = state.pop2()?; - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let res = builder.build_float_sub(v1, v2, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); + } + Operator::F64Sub => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_sub(v1, v2, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Sub => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64x2Sub => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } - Operator::F32Mul | Operator::F64Mul => { + Operator::F32Mul => { let (v1, v2) = state.pop2()?; - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let res = builder.build_float_mul(v1, v2, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); + } + Operator::F64Mul => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_mul(v1, v2, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Mul => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64x2Mul => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } - Operator::F32Div | Operator::F64Div => { + Operator::F32Div => { let (v1, v2) = state.pop2()?; - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let res = builder.build_float_div(v1, v2, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); + } + Operator::F64Div => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_div(v1, v2, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Div => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_div(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64x2Div => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_div(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32Sqrt => { let input = state.pop1()?; @@ -2658,7 +2866,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64Sqrt => { let input = state.pop1()?; @@ -2667,24 +2875,32 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Sqrt => { - let input = state.pop1()?.into_int_value(); - let float = builder.build_bitcast(input, intrinsics.f32x4_ty, "float"); + let (v, i) = state.pop1_extra()?; + let v = v128_into_f32x4(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.sqrt_f32x4, &[float], &state.var_name()) + .build_call( + intrinsics.sqrt_f32x4, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); let bits = builder.build_bitcast(res, intrinsics.i128_ty, "bits"); - state.push1(bits); + state.push1_extra(bits, ExtraInfo::PendingF32NaN); } Operator::F64x2Sqrt => { - let input = state.pop1()?.into_int_value(); - let float = builder.build_bitcast(input, intrinsics.f64x2_ty, "float"); + let (v, i) = state.pop1_extra()?; + let v = v128_into_f64x2(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.sqrt_f64x2, &[float], &state.var_name()) + .build_call( + intrinsics.sqrt_f64x2, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2692,87 +2908,479 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(bits); } Operator::F32Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.minimum_f32, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = intrinsics.f32_ty.const_float(-0.0); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F64Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.minimum_f64, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = intrinsics.f64_ty.const_float(-0.0); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F32x4Min => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let res = builder - .build_call(intrinsics.minimum_f32x4, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 8 and LLVM 9. + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. Note that this is a different + // canonicalization from that which may be performed in the + // v128_into_f32x4 function. That may canonicalize as F64x2 if + // previous computations may have emitted F64x2 NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1.as_basic_value_enum()); + let v2 = canonicalize_nans(builder, intrinsics, v2.as_basic_value_enum()); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32x4_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32x4_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32x4_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32x4_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = splat_vector( + builder, + intrinsics, + intrinsics.f32_ty.const_float(-0.0).as_basic_value_enum(), + intrinsics.f32x4_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F64x2Min => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let res = builder - .build_call(intrinsics.minimum_f64x2, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 8 and LLVM 9. + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. Note that this is a different + // canonicalization from that which may be performed in the + // v128_into_f32x4 function. That may canonicalize as F64x2 if + // previous computations may have emitted F64x2 NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1.as_basic_value_enum()); + let v2 = canonicalize_nans(builder, intrinsics, v2.as_basic_value_enum()); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64x2_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64x2_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64x2_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64x2_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = splat_vector( + builder, + intrinsics, + intrinsics.f64_ty.const_float(-0.0).as_basic_value_enum(), + intrinsics.f64x2_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F32Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.maximum_f32, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + intrinsics.f32_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F64Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.maximum_f64, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + intrinsics.f64_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F32x4Max => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let res = builder - .build_call(intrinsics.maximum_f32x4, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 8 and LLVM 9. + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. Note that this is a different + // canonicalization from that which may be performed in the + // v128_into_f32x4 function. That may canonicalize as F64x2 if + // previous computations may have emitted F64x2 NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1.as_basic_value_enum()); + let v2 = canonicalize_nans(builder, intrinsics, v2.as_basic_value_enum()); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32x4_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32x4_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32x4_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32x4_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let zero = splat_vector( + builder, + intrinsics, + intrinsics.f32_zero.as_basic_value_enum(), + intrinsics.f32x4_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F64x2Max => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let res = builder - .build_call(intrinsics.maximum_f64x2, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 8 and LLVM 9. + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. Note that this is a different + // canonicalization from that which may be performed in the + // v128_into_f32x4 function. That may canonicalize as F64x2 if + // previous computations may have emitted F64x2 NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1.as_basic_value_enum()); + let v2 = canonicalize_nans(builder, intrinsics, v2.as_basic_value_enum()); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64x2_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64x2_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64x2_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64x2_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let zero = splat_vector( + builder, + intrinsics, + intrinsics.f64_zero.as_basic_value_enum(), + intrinsics.f64x2_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F32Ceil => { @@ -2782,7 +3390,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64Ceil => { let input = state.pop1()?; @@ -2791,7 +3399,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32Floor => { let input = state.pop1()?; @@ -2800,7 +3408,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64Floor => { let input = state.pop1()?; @@ -2809,123 +3417,179 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32Trunc => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = builder - .build_call(intrinsics.trunc_f32, &[input], &state.var_name()) + .build_call( + intrinsics.trunc_f32, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, i); } Operator::F64Trunc => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = builder - .build_call(intrinsics.trunc_f64, &[input], &state.var_name()) + .build_call( + intrinsics.trunc_f64, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, i); } Operator::F32Nearest => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = builder - .build_call(intrinsics.nearbyint_f32, &[input], &state.var_name()) + .build_call( + intrinsics.nearbyint_f32, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, i); } Operator::F64Nearest => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = builder - .build_call(intrinsics.nearbyint_f64, &[input], &state.var_name()) + .build_call( + intrinsics.nearbyint_f64, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, i); } Operator::F32Abs => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.fabs_f32, &[input], &state.var_name()) + .build_call( + intrinsics.fabs_f32, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); + // The exact NaN returned by F32Abs is fully defined. Do not + // adjust. state.push1(res); } Operator::F64Abs => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.fabs_f64, &[input], &state.var_name()) + .build_call( + intrinsics.fabs_f64, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); + // The exact NaN returned by F64Abs is fully defined. Do not + // adjust. state.push1(res); } Operator::F32x4Abs => { - let v = state.pop1()?.into_int_value(); - let v = builder.build_bitcast(v, intrinsics.f32x4_ty, ""); + let (v, i) = state.pop1_extra()?; + let v = builder.build_bitcast(v.into_int_value(), intrinsics.f32x4_ty, ""); + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.fabs_f32x4, &[v], &state.var_name()) + .build_call( + intrinsics.fabs_f32x4, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // The exact NaN returned by F32x4Abs is fully defined. Do not + // adjust. state.push1(res); } Operator::F64x2Abs => { - let v = state.pop1()?.into_int_value(); - let v = builder.build_bitcast(v, intrinsics.f64x2_ty, ""); + let (v, i) = state.pop1_extra()?; + let v = builder.build_bitcast(v.into_int_value(), intrinsics.f64x2_ty, ""); + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let res = builder .build_call(intrinsics.fabs_f64x2, &[v], &state.var_name()) .try_as_basic_value() .left() .unwrap(); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // The exact NaN returned by F32x4Abs is fully defined. Do not + // adjust. state.push1(res); } Operator::F32x4Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.f32x4_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = builder.build_bitcast(v.into_int_value(), intrinsics.f32x4_ty, ""); + let v = + apply_pending_canonicalization(builder, intrinsics, v, i).into_vector_value(); let res = builder.build_float_neg(v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // The exact NaN returned by F32x4Neg is fully defined. Do not + // adjust. state.push1(res); } Operator::F64x2Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.f64x2_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = builder.build_bitcast(v.into_int_value(), intrinsics.f64x2_ty, ""); + let v = + apply_pending_canonicalization(builder, intrinsics, v, i).into_vector_value(); let res = builder.build_float_neg(v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // The exact NaN returned by F64x2Neg is fully defined. Do not + // adjust. state.push1(res); } Operator::F32Neg | Operator::F64Neg => { - let input = state.pop1()?.into_float_value(); - let res = builder.build_float_neg(input, &state.var_name()); + let (v, i) = state.pop1_extra()?; + let v = + apply_pending_canonicalization(builder, intrinsics, v, i).into_float_value(); + let res = builder.build_float_neg(v, &state.var_name()); + // The exact NaN returned by F32Neg and F64Neg are fully defined. + // Do not adjust. state.push1(res); } Operator::F32Copysign => { - let (mag, sgn) = state.pop2()?; + let ((mag, mag_info), (sgn, sgn_info)) = state.pop2_extra()?; + let mag = apply_pending_canonicalization(builder, intrinsics, mag, mag_info); + let sgn = apply_pending_canonicalization(builder, intrinsics, sgn, sgn_info); let res = builder .build_call(intrinsics.copysign_f32, &[mag, sgn], &state.var_name()) .try_as_basic_value() .left() .unwrap(); + // The exact NaN returned by F32Copysign is fully defined. + // Do not adjust. state.push1(res); } Operator::F64Copysign => { - let (msg, sgn) = state.pop2()?; + let ((mag, mag_info), (sgn, sgn_info)) = state.pop2_extra()?; + let mag = apply_pending_canonicalization(builder, intrinsics, mag, mag_info); + let sgn = apply_pending_canonicalization(builder, intrinsics, sgn, sgn_info); let res = builder - .build_call(intrinsics.copysign_f64, &[msg, sgn], &state.var_name()) + .build_call(intrinsics.copysign_f64, &[mag, sgn], &state.var_name()) .try_as_basic_value() .left() .unwrap(); + // The exact NaN returned by F32Copysign is fully defined. + // Do not adjust. state.push1(res); } @@ -2941,39 +3605,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -2987,39 +3639,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::NE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::NE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::NE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3033,39 +3673,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16LtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8LtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4LtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3079,39 +3707,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16LtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8LtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4LtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3125,39 +3741,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16LeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8LeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4LeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3171,39 +3775,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16LeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8LeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4LeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3217,39 +3809,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16GtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8GtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4GtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3263,39 +3843,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16GtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8GtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4GtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3309,39 +3877,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16GeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8GeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4GeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3355,39 +3911,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16GeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8GeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4GeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3407,26 +3951,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3441,26 +3977,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::UNE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::UNE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3475,26 +4003,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Lt => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Lt => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3509,26 +4029,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Le => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Le => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3543,26 +4055,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Gt => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Gt => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3577,26 +4081,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Ge => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Ge => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3816,16 +4312,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32DemoteF64 => { - let v1 = state.pop1()?; - let v1 = canonicalize_nans(builder, intrinsics, v1).into_float_value(); - let res = builder.build_float_trunc(v1, intrinsics.f32_ty, &state.var_name()); - state.push1(res); + let v = state.pop1()?; + let v = v.into_float_value(); + let res = builder.build_float_trunc(v, intrinsics.f32_ty, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64PromoteF32 => { - let v1 = state.pop1()?; - let v1 = canonicalize_nans(builder, intrinsics, v1).into_float_value(); - let res = builder.build_float_ext(v1, intrinsics.f64_ty, &state.var_name()); - state.push1(res); + let v = state.pop1()?; + let v = v.into_float_value(); + let res = builder.build_float_ext(v, intrinsics.f64_ty, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32ConvertSI32 | Operator::F32ConvertSI64 => { let v1 = state.pop1()?.into_int_value(); @@ -3892,12 +4388,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32ReinterpretF32 => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let ret = builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()); state.push1(ret); } Operator::I64ReinterpretF64 => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let ret = builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()); state.push1(ret); } @@ -3966,6 +4464,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -3974,6 +4473,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let result = builder.build_load(effective_address, &state.var_name()); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } Operator::I64Load { ref memarg } => { @@ -3981,6 +4487,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -3989,6 +4496,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let result = builder.build_load(effective_address, &state.var_name()); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } Operator::F32Load { ref memarg } => { @@ -3996,6 +4510,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4004,6 +4519,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 4, )?; let result = builder.build_load(effective_address, &state.var_name()); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } Operator::F64Load { ref memarg } => { @@ -4011,6 +4533,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4019,6 +4542,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 8, )?; let result = builder.build_load(effective_address, &state.var_name()); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } Operator::V128Load { ref memarg } => { @@ -4026,6 +4556,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4034,6 +4565,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { 16, )?; let result = builder.build_load(effective_address, &state.var_name()); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } @@ -4043,6 +4581,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4050,7 +4589,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i32_ptr_ty, 4, )?; - builder.build_store(effective_address, value); + let store = builder.build_store(effective_address, value); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64Store { ref memarg } => { let value = state.pop1()?; @@ -4058,6 +4598,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4065,14 +4606,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i64_ptr_ty, 8, )?; - builder.build_store(effective_address, value); + let store = builder.build_store(effective_address, value); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::F32Store { ref memarg } => { - let value = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let effective_address = resolve_memory_ptr( builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4080,14 +4624,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.f32_ptr_ty, 4, )?; - builder.build_store(effective_address, value); + let store = builder.build_store(effective_address, v); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::F64Store { ref memarg } => { - let value = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let effective_address = resolve_memory_ptr( builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4095,14 +4642,17 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.f64_ptr_ty, 8, )?; - builder.build_store(effective_address, value); + let store = builder.build_store(effective_address, v); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::V128Store { ref memarg } => { - let value = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let effective_address = resolve_memory_ptr( builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4110,14 +4660,15 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i128_ptr_ty, 16, )?; - builder.build_store(effective_address, value); + let store = builder.build_store(effective_address, v); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } - Operator::I32Load8S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4128,6 +4679,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); @@ -4137,6 +4695,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4144,11 +4703,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i16_ptr_ty, 2, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); + let result = builder.build_int_s_extend( + narrow_result.into_int_value(), + intrinsics.i32_ty, + &state.var_name(), + ); state.push1(result); } Operator::I64Load8S { ref memarg } => { @@ -4156,6 +4723,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4166,6 +4734,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -4175,6 +4750,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4185,6 +4761,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -4194,6 +4777,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4204,6 +4788,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -4214,6 +4805,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4224,6 +4816,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); @@ -4233,6 +4832,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4243,6 +4843,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); @@ -4252,6 +4859,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4262,6 +4870,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -4271,6 +4886,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4281,6 +4897,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -4290,6 +4913,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4300,6 +4924,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -4311,6 +4942,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4320,7 +4952,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; let narrow_value = builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); - builder.build_store(effective_address, narrow_value); + let store = builder.build_store(effective_address, narrow_value); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32Store16 { ref memarg } | Operator::I64Store16 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -4328,6 +4961,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4337,7 +4971,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; let narrow_value = builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); - builder.build_store(effective_address, narrow_value); + let store = builder.build_store(effective_address, narrow_value); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64Store32 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -4345,6 +4980,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4354,46 +4990,40 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { )?; let narrow_value = builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); - builder.build_store(effective_address, narrow_value); + let store = builder.build_store(effective_address, narrow_value); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I8x16Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i8x16_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i8x16(builder, intrinsics, v, i); let res = builder.build_int_sub(v.get_type().const_zero(), v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i16x8_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i16x8(builder, intrinsics, v, i); let res = builder.build_int_sub(v.get_type().const_zero(), v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i32x4_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i32x4(builder, intrinsics, v, i); let res = builder.build_int_sub(v.get_type().const_zero(), v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I64x2Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i64x2_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i64x2(builder, intrinsics, v, i); let res = builder.build_int_sub(v.get_type().const_zero(), v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::V128Not => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i).into_int_value(); let res = builder.build_not(v, &state.var_name()); state.push1(res); } @@ -4401,7 +5031,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { | Operator::I16x8AnyTrue | Operator::I32x4AnyTrue | Operator::I64x2AnyTrue => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i).into_int_value(); let res = builder.build_int_compare( IntPredicate::NE, v, @@ -4422,7 +5053,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::I64x2AllTrue => intrinsics.i64x2_ty, _ => unreachable!(), }; - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i).into_int_value(); let lane_int_ty = context.custom_width_int_type(vec_ty.get_size()); let vec = builder.build_bitcast(v, vec_ty, "vec").into_vector_value(); let mask = @@ -4440,10 +5072,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16ExtractLaneS { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i8x16_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i8x16(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder .build_extract_element(v, idx, &state.var_name()) @@ -4452,10 +5082,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16ExtractLaneU { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i8x16_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i8x16(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder .build_extract_element(v, idx, &state.var_name()) @@ -4464,10 +5092,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ExtractLaneS { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i16x8_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i16x8(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder .build_extract_element(v, idx, &state.var_name()) @@ -4476,10 +5102,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ExtractLaneU { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i16x8_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i16x8(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder .build_extract_element(v, idx, &state.var_name()) @@ -4488,46 +5112,36 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ExtractLane { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i32x4_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i32x4(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_extract_element(v, idx, &state.var_name()); state.push1(res); } Operator::I64x2ExtractLane { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i64x2_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i64x2(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_extract_element(v, idx, &state.var_name()); state.push1(res); } Operator::F32x4ExtractLane { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.f32x4_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_f32x4(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_extract_element(v, idx, &state.var_name()); state.push1(res); } Operator::F64x2ExtractLane { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.f64x2_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_f64x2(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_extract_element(v, idx, &state.var_name()); state.push1(res); } Operator::I8x16ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_int_cast(v2, intrinsics.i8_ty, ""); let idx = intrinsics.i32_ty.const_int(lane.into(), false); @@ -4536,10 +5150,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_int_cast(v2, intrinsics.i16_ty, ""); let idx = intrinsics.i32_ty.const_int(lane.into(), false); @@ -4548,10 +5160,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_insert_element(v1, v2, idx, &state.var_name()); @@ -4559,10 +5169,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_insert_element(v1, v2, idx, &state.var_name()); @@ -4570,32 +5178,32 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = v2.into_float_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = + apply_pending_canonicalization(builder, intrinsics, v2, i2).into_float_value(); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_insert_element(v1, v2, idx, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = v2.into_float_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = + apply_pending_canonicalization(builder, intrinsics, v2, i2).into_float_value(); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_insert_element(v1, v2, idx, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::V8x16Swizzle => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); let v1 = builder .build_bitcast(v1, intrinsics.i8x16_ty, "") .into_vector_value(); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let v2 = builder .build_bitcast(v2, intrinsics.i8x16_ty, "") .into_vector_value(); @@ -4653,10 +5261,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::V8x16Shuffle { lanes } => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); let v1 = builder .build_bitcast(v1, intrinsics.i8x16_ty, "") .into_vector_value(); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let v2 = builder .build_bitcast(v2, intrinsics.i8x16_ty, "") .into_vector_value(); @@ -4676,6 +5286,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4683,11 +5294,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i8_ptr_ty, 1, )?; - let elem = builder.build_load(effective_address, "").into_int_value(); + let elem = builder.build_load(effective_address, ""); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + elem.as_instruction_value().unwrap(), + Some(0), + ); let res = splat_vector( builder, intrinsics, - elem.as_basic_value_enum(), + elem, intrinsics.i8x16_ty, &state.var_name(), ); @@ -4699,6 +5317,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4706,11 +5325,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i16_ptr_ty, 2, )?; - let elem = builder.build_load(effective_address, "").into_int_value(); + let elem = builder.build_load(effective_address, ""); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + elem.as_instruction_value().unwrap(), + Some(0), + ); let res = splat_vector( builder, intrinsics, - elem.as_basic_value_enum(), + elem, intrinsics.i16x8_ty, &state.var_name(), ); @@ -4722,6 +5348,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4729,11 +5356,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i32_ptr_ty, 4, )?; - let elem = builder.build_load(effective_address, "").into_int_value(); + let elem = builder.build_load(effective_address, ""); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + elem.as_instruction_value().unwrap(), + Some(0), + ); let res = splat_vector( builder, intrinsics, - elem.as_basic_value_enum(), + elem, intrinsics.i32x4_ty, &state.var_name(), ); @@ -4745,6 +5379,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4752,11 +5387,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i64_ptr_ty, 8, )?; - let elem = builder.build_load(effective_address, "").into_int_value(); + let elem = builder.build_load(effective_address, ""); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + elem.as_instruction_value().unwrap(), + Some(0), + ); let res = splat_vector( builder, intrinsics, - elem.as_basic_value_enum(), + elem, intrinsics.i64x2_ty, &state.var_name(), ); @@ -4777,6 +5419,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4797,6 +5440,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(4).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); state.push1(result); } Operator::I64AtomicLoad { ref memarg } => { @@ -4804,6 +5448,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4824,6 +5469,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(8).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); state.push1(result); } Operator::I32AtomicLoad8U { ref memarg } => { @@ -4831,6 +5477,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4853,6 +5500,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(1).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); @@ -4862,6 +5510,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4884,6 +5533,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(2).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); @@ -4893,6 +5543,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4915,6 +5566,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(1).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -4924,6 +5576,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4946,6 +5599,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(2).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -4955,6 +5609,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -4977,6 +5632,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(4).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -4987,6 +5643,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5007,6 +5664,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64AtomicStore { ref memarg } => { let value = state.pop1()?; @@ -5014,6 +5672,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5034,6 +5693,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32AtomicStore8 { ref memarg } | Operator::I64AtomicStore8 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5041,6 +5701,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5063,6 +5724,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32AtomicStore16 { ref memarg } | Operator::I64AtomicStore16 { ref memarg } => { @@ -5071,6 +5733,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5093,6 +5756,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64AtomicStore32 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5100,6 +5764,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5122,6 +5787,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32AtomicRmw8UAdd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5129,6 +5795,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5154,6 +5821,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5163,6 +5837,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5188,6 +5863,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5197,6 +5879,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5220,6 +5903,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8UAdd { ref memarg } => { @@ -5228,6 +5918,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5253,6 +5944,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5262,6 +5960,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5287,6 +5986,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5296,6 +6002,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5321,6 +6028,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5330,6 +6044,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5353,6 +6068,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8USub { ref memarg } => { @@ -5361,6 +6083,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5386,6 +6109,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5395,6 +6125,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5420,6 +6151,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5429,6 +6167,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5452,6 +6191,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8USub { ref memarg } => { @@ -5460,6 +6206,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5485,6 +6232,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5494,6 +6248,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5519,6 +6274,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5528,6 +6290,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5553,6 +6316,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5562,6 +6332,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5585,6 +6356,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UAnd { ref memarg } => { @@ -5593,6 +6371,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5618,6 +6397,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5627,6 +6413,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5652,6 +6439,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5661,6 +6455,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5684,6 +6479,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8UAnd { ref memarg } => { @@ -5692,6 +6494,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5717,6 +6520,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5726,6 +6536,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5751,6 +6562,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5760,6 +6578,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5785,6 +6604,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5794,6 +6620,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5817,6 +6644,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UOr { ref memarg } => { @@ -5825,6 +6659,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5850,6 +6685,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5859,6 +6701,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5884,6 +6727,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5893,6 +6743,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5916,6 +6767,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5925,6 +6783,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5950,6 +6809,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5959,6 +6825,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -5984,6 +6851,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5993,6 +6867,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6018,6 +6893,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6027,6 +6909,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6050,6 +6933,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UXor { ref memarg } => { @@ -6058,6 +6948,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6083,6 +6974,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6092,6 +6990,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6117,6 +7016,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6126,6 +7032,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6149,6 +7056,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8UXor { ref memarg } => { @@ -6157,6 +7071,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6182,6 +7097,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6191,6 +7113,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6216,6 +7139,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6225,6 +7155,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6250,6 +7181,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6259,6 +7197,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6282,6 +7221,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UXchg { ref memarg } => { @@ -6290,6 +7236,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6315,6 +7262,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6324,6 +7278,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6349,6 +7304,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6358,6 +7320,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6381,6 +7344,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8UXchg { ref memarg } => { @@ -6389,6 +7359,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6414,6 +7385,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6423,6 +7401,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6448,6 +7427,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6457,6 +7443,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6482,6 +7469,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6491,6 +7485,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6514,6 +7509,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UCmpxchg { ref memarg } => { @@ -6523,6 +7525,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6551,6 +7554,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -6565,6 +7575,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6593,6 +7604,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -6607,6 +7625,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6631,6 +7650,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_extract_value(old, 0, "").unwrap(); state.push1(old); } @@ -6641,6 +7667,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6669,6 +7696,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -6683,6 +7717,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6711,6 +7746,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -6725,6 +7767,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6753,6 +7796,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -6767,6 +7817,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, @@ -6791,6 +7842,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_extract_value(old, 0, "").unwrap(); state.push1(old); } @@ -6872,15 +7930,21 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } fn finalize(&mut self) -> Result<(), CodegenError> { - let results = self.state.popn_save(self.func_sig.returns().len())?; + let results = self.state.popn_save_extra(self.func_sig.returns().len())?; match results.as_slice() { [] => { self.builder.as_ref().unwrap().build_return(None); } - [one_value] => { + [(one_value, one_value_info)] => { let builder = self.builder.as_ref().unwrap(); let intrinsics = self.intrinsics.as_ref().unwrap(); + let one_value = apply_pending_canonicalization( + builder, + intrinsics, + *one_value, + *one_value_info, + ); builder.build_return(Some(&builder.build_bitcast( one_value.as_basic_value_enum(), type_to_llvm_int_only(intrinsics, self.func_sig.returns()[0]), @@ -6911,6 +7975,31 @@ impl ModuleCodeGenerator fn new() -> LLVMModuleCodeGenerator { let context = Context::create(); let module = context.create_module("module"); + + Target::initialize_x86(&InitializationConfig { + asm_parser: true, + asm_printer: true, + base: true, + disassembler: true, + info: true, + machine_code: true, + }); + let triple = TargetMachine::get_default_triple().to_string(); + let target = Target::from_triple(&triple).unwrap(); + let target_machine = target + .create_target_machine( + &triple, + &TargetMachine::get_host_cpu_name().to_string(), + &TargetMachine::get_host_cpu_features().to_string(), + OptimizationLevel::Aggressive, + RelocMode::Static, + CodeModel::Large, + ) + .unwrap(); + + module.set_target(&target); + module.set_data_layout(&target_machine.get_target_data().get_data_layout()); + let builder = context.create_builder(); let intrinsics = Intrinsics::declare(&module, &context); @@ -6921,20 +8010,20 @@ impl ModuleCodeGenerator Some(Linkage::External), ); - let signatures = Map::new(); - LLVMModuleCodeGenerator { context: Some(context), builder: Some(builder), intrinsics: Some(intrinsics), - module, + module: Rc::new(RefCell::new(module)), functions: vec![], - signatures, + signatures: Map::new(), signatures_raw: Map::new(), function_signatures: None, func_import_count: 0, personality_func, stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), + track_state: false, + target_machine, } } @@ -6968,7 +8057,7 @@ impl ModuleCodeGenerator [FuncIndex::new(self.func_import_count + self.functions.len())]; let func_sig = self.signatures_raw[sig_id].clone(); - let function = self.module.add_function( + let function = self.module.borrow_mut().add_function( &format!("fn{}", self.func_import_count + self.functions.len()), self.signatures[sig_id], Some(Linkage::External), @@ -6977,6 +8066,8 @@ impl ModuleCodeGenerator let mut state = State::new(); let entry_block = context.append_basic_block(&function, "entry"); + let alloca_builder = context.create_builder(); + alloca_builder.position_at_end(&entry_block); let return_block = context.append_basic_block(&function, "return"); builder.position_at_end(&return_block); @@ -6998,20 +8089,23 @@ impl ModuleCodeGenerator .skip(1) .enumerate() .map(|(index, param)| { - //let ty = param.get_type(); let real_ty = func_sig.params()[index]; let real_ty_llvm = type_to_llvm(&intrinsics, real_ty); - - let alloca = builder.build_alloca(real_ty_llvm, &format!("local{}", index)); - - //if real_ty_llvm != ty { + let alloca = + alloca_builder.build_alloca(real_ty_llvm, &format!("local{}", index)); builder.build_store( alloca, builder.build_bitcast(param, real_ty_llvm, &state.var_name()), ); - /*} else { - builder.build_store(alloca, param); - }*/ + if index == 0 { + alloca_builder.position_before( + &alloca + .as_instruction() + .unwrap() + .get_next_instruction() + .unwrap(), + ); + } alloca }), ); @@ -7023,6 +8117,7 @@ impl ModuleCodeGenerator state, context: Some(context), builder: Some(builder), + alloca_builder: Some(alloca_builder), intrinsics: Some(intrinsics), function, func_sig: func_sig, @@ -7034,6 +8129,8 @@ impl ModuleCodeGenerator stackmaps: self.stackmaps.clone(), index: local_func_index, opcode_offset: 0, + track_state: self.track_state, + module: self.module.clone(), }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) @@ -7062,7 +8159,7 @@ impl ModuleCodeGenerator generate_trampolines( module_info, &self.signatures, - &self.module, + &self.module.borrow_mut(), self.context.as_ref().unwrap(), self.builder.as_ref().unwrap(), self.intrinsics.as_ref().unwrap(), @@ -7072,13 +8169,14 @@ impl ModuleCodeGenerator })?; if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.pre_opt_ir } { - self.module.print_to_file(path).unwrap(); + self.module.borrow_mut().print_to_file(path).unwrap(); } let pass_manager = PassManager::create(()); if cfg!(test) { pass_manager.add_verifier_pass(); } + pass_manager.add_type_based_alias_analysis_pass(); pass_manager.add_lower_expect_intrinsic_pass(); pass_manager.add_scalar_repl_aggregates_pass(); pass_manager.add_instruction_combining_pass(); @@ -7092,23 +8190,29 @@ impl ModuleCodeGenerator pass_manager.add_cfg_simplification_pass(); pass_manager.add_bit_tracking_dce_pass(); pass_manager.add_slp_vectorize_pass(); - pass_manager.run_on(&self.module); + pass_manager.run_on(&*self.module.borrow_mut()); if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.post_opt_ir } { - self.module.print_to_file(path).unwrap(); + self.module.borrow_mut().print_to_file(path).unwrap(); } let stackmaps = self.stackmaps.borrow(); let (backend, cache_gen) = LLVMBackend::new( - self.module, + self.module.clone(), self.intrinsics.take().unwrap(), &*stackmaps, module_info, + &self.target_machine, ); Ok((backend, Box::new(cache_gen))) } + fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), CodegenError> { + self.track_state = config.track_state; + Ok(()) + } + fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { self.signatures = signatures .iter() diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 278e087bb..4c34b6d58 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -6,11 +6,16 @@ use inkwell::{ types::{ BasicType, FloatType, FunctionType, IntType, PointerType, StructType, VectorType, VoidType, }, - values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue}, + values::{ + BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, + PointerValue, VectorValue, + }, AddressSpace, }; +use std::cell::RefCell; use std::collections::HashMap; use std::marker::PhantomData; +use std::rc::Rc; use wasmer_runtime_core::{ memory::MemoryType, module::ModuleInfo, @@ -19,6 +24,7 @@ use wasmer_runtime_core::{ GlobalIndex, ImportedFuncIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, }, + units::Pages, vm::{Ctx, INTERNALS_SIZE}, }; @@ -47,16 +53,6 @@ pub struct Intrinsics { pub sqrt_f32x4: FunctionValue, pub sqrt_f64x2: FunctionValue, - pub minimum_f32: FunctionValue, - pub minimum_f64: FunctionValue, - pub minimum_f32x4: FunctionValue, - pub minimum_f64x2: FunctionValue, - - pub maximum_f32: FunctionValue, - pub maximum_f64: FunctionValue, - pub maximum_f32x4: FunctionValue, - pub maximum_f64x2: FunctionValue, - pub ceil_f32: FunctionValue, pub ceil_f64: FunctionValue, @@ -125,6 +121,8 @@ pub struct Intrinsics { pub i128_zero: IntValue, pub f32_zero: FloatValue, pub f64_zero: FloatValue, + pub f32x4_zero: VectorValue, + pub f64x2_zero: VectorValue, pub trap_unreachable: BasicValueEnum, pub trap_call_indirect_sig: BasicValueEnum, @@ -191,6 +189,8 @@ impl Intrinsics { let i128_zero = i128_ty.const_int(0, false); let f32_zero = f32_ty.const_float(0.0); let f64_zero = f64_ty.const_float(0.0); + let f32x4_zero = f32x4_ty.const_zero(); + let f64x2_zero = f64x2_ty.const_zero(); let i1_ty_basic = i1_ty.as_basic_type_enum(); let i32_ty_basic = i32_ty.as_basic_type_enum(); @@ -303,8 +303,6 @@ impl Intrinsics { let ret_f32_take_f32_f32 = f32_ty.fn_type(&[f32_ty_basic, f32_ty_basic], false); let ret_f64_take_f64_f64 = f64_ty.fn_type(&[f64_ty_basic, f64_ty_basic], false); - let ret_f32x4_take_f32x4_f32x4 = f32x4_ty.fn_type(&[f32x4_ty_basic, f32x4_ty_basic], false); - let ret_f64x2_take_f64x2_f64x2 = f64x2_ty.fn_type(&[f64x2_ty_basic, f64x2_ty_basic], false); let ret_i32_take_ctx_i32_i32 = i32_ty.fn_type( &[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic], @@ -329,32 +327,6 @@ impl Intrinsics { sqrt_f32x4: module.add_function("llvm.sqrt.v4f32", ret_f32x4_take_f32x4, None), sqrt_f64x2: module.add_function("llvm.sqrt.v2f64", ret_f64x2_take_f64x2, None), - minimum_f32: module.add_function("llvm.minnum.f32", ret_f32_take_f32_f32, None), - minimum_f64: module.add_function("llvm.minnum.f64", ret_f64_take_f64_f64, None), - minimum_f32x4: module.add_function( - "llvm.minnum.v4f32", - ret_f32x4_take_f32x4_f32x4, - None, - ), - minimum_f64x2: module.add_function( - "llvm.minnum.v2f64", - ret_f64x2_take_f64x2_f64x2, - None, - ), - - maximum_f32: module.add_function("llvm.maxnum.f32", ret_f32_take_f32_f32, None), - maximum_f64: module.add_function("llvm.maxnum.f64", ret_f64_take_f64_f64, None), - maximum_f32x4: module.add_function( - "llvm.maxnum.v4f32", - ret_f32x4_take_f32x4_f32x4, - None, - ), - maximum_f64x2: module.add_function( - "llvm.maxnum.v2f64", - ret_f64x2_take_f64x2_f64x2, - None, - ), - ceil_f32: module.add_function("llvm.ceil.f32", ret_f32_take_f32, None), ceil_f64: module.add_function("llvm.ceil.f64", ret_f64_take_f64, None), @@ -455,6 +427,8 @@ impl Intrinsics { i128_zero, f32_zero, f64_zero, + f32x4_zero, + f64x2_zero, trap_unreachable: i32_zero.as_basic_value_enum(), trap_call_indirect_sig: i32_ty.const_int(1, false).as_basic_value_enum(), @@ -589,11 +563,15 @@ pub enum MemoryCache { Dynamic { ptr_to_base_ptr: PointerValue, ptr_to_bounds: PointerValue, + minimum: Pages, + maximum: Option, }, /// The memory is always in the same place. Static { base_ptr: PointerValue, bounds: IntValue, + minimum: Pages, + maximum: Option, }, } @@ -683,7 +661,12 @@ impl<'a> CtxType<'a> { ptr } - pub fn memory(&mut self, index: MemoryIndex, intrinsics: &Intrinsics) -> MemoryCache { + pub fn memory( + &mut self, + index: MemoryIndex, + intrinsics: &Intrinsics, + module: Rc>, + ) -> MemoryCache { let (cached_memories, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_memories, self.info, @@ -692,34 +675,48 @@ impl<'a> CtxType<'a> { ); *cached_memories.entry(index).or_insert_with(|| { - let (memory_array_ptr_ptr, index, memory_type) = match index.local_or_import(info) { - LocalOrImport::Local(local_mem_index) => ( - unsafe { - cache_builder.build_struct_gep( - ctx_ptr_value, - offset_to_index(Ctx::offset_memories()), - "memory_array_ptr_ptr", - ) - }, - local_mem_index.index() as u64, - info.memories[local_mem_index].memory_type(), - ), - LocalOrImport::Import(import_mem_index) => ( - unsafe { - cache_builder.build_struct_gep( - ctx_ptr_value, - offset_to_index(Ctx::offset_imported_memories()), - "memory_array_ptr_ptr", - ) - }, - import_mem_index.index() as u64, - info.imported_memories[import_mem_index].1.memory_type(), - ), - }; + let (memory_array_ptr_ptr, index, memory_type, minimum, maximum, field_name) = + match index.local_or_import(info) { + LocalOrImport::Local(local_mem_index) => ( + unsafe { + cache_builder.build_struct_gep( + ctx_ptr_value, + offset_to_index(Ctx::offset_memories()), + "memory_array_ptr_ptr", + ) + }, + local_mem_index.index() as u64, + info.memories[local_mem_index].memory_type(), + info.memories[local_mem_index].minimum, + info.memories[local_mem_index].maximum, + "context_field_ptr_to_local_memory", + ), + LocalOrImport::Import(import_mem_index) => ( + unsafe { + cache_builder.build_struct_gep( + ctx_ptr_value, + offset_to_index(Ctx::offset_imported_memories()), + "memory_array_ptr_ptr", + ) + }, + import_mem_index.index() as u64, + info.imported_memories[import_mem_index].1.memory_type(), + info.imported_memories[import_mem_index].1.minimum, + info.imported_memories[import_mem_index].1.maximum, + "context_field_ptr_to_imported_memory", + ), + }; let memory_array_ptr = cache_builder .build_load(memory_array_ptr_ptr, "memory_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + field_name, + memory_array_ptr.as_instruction_value().unwrap(), + None, + ); let const_index = intrinsics.i32_ty.const_int(index, false); let memory_ptr_ptr = unsafe { cache_builder.build_in_bounds_gep( @@ -731,6 +728,13 @@ impl<'a> CtxType<'a> { let memory_ptr = cache_builder .build_load(memory_ptr_ptr, "memory_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "memory_ptr", + memory_ptr.as_instruction_value().unwrap(), + Some(index as u32), + ); let (ptr_to_base_ptr, ptr_to_bounds) = unsafe { ( @@ -743,15 +747,37 @@ impl<'a> CtxType<'a> { MemoryType::Dynamic => MemoryCache::Dynamic { ptr_to_base_ptr, ptr_to_bounds, + minimum, + maximum, }, - MemoryType::Static | MemoryType::SharedStatic => MemoryCache::Static { - base_ptr: cache_builder + MemoryType::Static | MemoryType::SharedStatic => { + let base_ptr = cache_builder .build_load(ptr_to_base_ptr, "base") - .into_pointer_value(), - bounds: cache_builder + .into_pointer_value(); + let bounds = cache_builder .build_load(ptr_to_bounds, "bounds") - .into_int_value(), - }, + .into_int_value(); + tbaa_label( + module.clone(), + intrinsics, + "static_memory_base", + base_ptr.as_instruction_value().unwrap(), + Some(index as u32), + ); + tbaa_label( + module.clone(), + intrinsics, + "static_memory_bounds", + bounds.as_instruction_value().unwrap(), + Some(index as u32), + ); + MemoryCache::Static { + base_ptr, + bounds, + minimum, + maximum, + } + } } }) } @@ -760,6 +786,7 @@ impl<'a> CtxType<'a> { &mut self, index: TableIndex, intrinsics: &Intrinsics, + module: Rc>, ) -> (PointerValue, PointerValue) { let (cached_tables, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_tables, @@ -772,7 +799,7 @@ impl<'a> CtxType<'a> { ptr_to_base_ptr, ptr_to_bounds, } = *cached_tables.entry(index).or_insert_with(|| { - let (table_array_ptr_ptr, index) = match index.local_or_import(info) { + let (table_array_ptr_ptr, index, field_name) = match index.local_or_import(info) { LocalOrImport::Local(local_table_index) => ( unsafe { cache_builder.build_struct_gep( @@ -782,6 +809,7 @@ impl<'a> CtxType<'a> { ) }, local_table_index.index() as u64, + "context_field_ptr_to_local_table", ), LocalOrImport::Import(import_table_index) => ( unsafe { @@ -792,12 +820,20 @@ impl<'a> CtxType<'a> { ) }, import_table_index.index() as u64, + "context_field_ptr_to_import_table", ), }; let table_array_ptr = cache_builder .build_load(table_array_ptr_ptr, "table_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + field_name, + table_array_ptr.as_instruction_value().unwrap(), + None, + ); let const_index = intrinsics.i32_ty.const_int(index, false); let table_ptr_ptr = unsafe { cache_builder.build_in_bounds_gep(table_array_ptr, &[const_index], "table_ptr_ptr") @@ -805,6 +841,13 @@ impl<'a> CtxType<'a> { let table_ptr = cache_builder .build_load(table_ptr_ptr, "table_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "table_ptr", + table_array_ptr.as_instruction_value().unwrap(), + Some(index as u32), + ); let (ptr_to_base_ptr, ptr_to_bounds) = unsafe { ( @@ -826,15 +869,30 @@ impl<'a> CtxType<'a> { &mut self, index: TableIndex, intrinsics: &Intrinsics, + module: Rc>, builder: &Builder, ) -> (PointerValue, IntValue) { - let (ptr_to_base_ptr, ptr_to_bounds) = self.table_prepare(index, intrinsics); - ( - builder - .build_load(ptr_to_base_ptr, "base_ptr") - .into_pointer_value(), - builder.build_load(ptr_to_bounds, "bounds").into_int_value(), - ) + let (ptr_to_base_ptr, ptr_to_bounds) = + self.table_prepare(index, intrinsics, module.clone()); + let base_ptr = builder + .build_load(ptr_to_base_ptr, "base_ptr") + .into_pointer_value(); + let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value(); + tbaa_label( + module.clone(), + intrinsics, + "table_base_ptr", + base_ptr.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); + tbaa_label( + module.clone(), + intrinsics, + "table_bounds", + bounds.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); + (base_ptr, bounds) } pub fn local_func( @@ -842,6 +900,7 @@ impl<'a> CtxType<'a> { index: LocalFuncIndex, fn_ty: FunctionType, intrinsics: &Intrinsics, + module: Rc>, builder: &Builder, ) -> PointerValue { let local_func_array_ptr_ptr = unsafe { @@ -854,6 +913,13 @@ impl<'a> CtxType<'a> { let local_func_array_ptr = builder .build_load(local_func_array_ptr_ptr, "local_func_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_local_funcs", + local_func_array_ptr.as_instruction_value().unwrap(), + None, + ); let local_func_ptr_ptr = unsafe { builder.build_in_bounds_gep( local_func_array_ptr, @@ -864,6 +930,13 @@ impl<'a> CtxType<'a> { let local_func_ptr = builder .build_load(local_func_ptr_ptr, "local_func_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "local_func_ptr", + local_func_ptr.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); builder.build_pointer_cast( local_func_ptr, fn_ty.ptr_type(AddressSpace::Generic), @@ -905,7 +978,12 @@ impl<'a> CtxType<'a> { }) } - pub fn global_cache(&mut self, index: GlobalIndex, intrinsics: &Intrinsics) -> GlobalCache { + pub fn global_cache( + &mut self, + index: GlobalIndex, + intrinsics: &Intrinsics, + module: Rc>, + ) -> GlobalCache { let (cached_globals, ctx_ptr_value, info, cache_builder) = ( &mut self.cached_globals, self.ctx_ptr_value, @@ -914,7 +992,7 @@ impl<'a> CtxType<'a> { ); *cached_globals.entry(index).or_insert_with(|| { - let (globals_array_ptr_ptr, index, mutable, wasmer_ty) = + let (globals_array_ptr_ptr, index, mutable, wasmer_ty, field_name) = match index.local_or_import(info) { LocalOrImport::Local(local_global_index) => { let desc = info.globals[local_global_index].desc; @@ -929,6 +1007,7 @@ impl<'a> CtxType<'a> { local_global_index.index() as u64, desc.mutable, desc.ty, + "context_field_ptr_to_local_globals", ) } LocalOrImport::Import(import_global_index) => { @@ -944,6 +1023,7 @@ impl<'a> CtxType<'a> { import_global_index.index() as u64, desc.mutable, desc.ty, + "context_field_ptr_to_imported_globals", ) } }; @@ -953,6 +1033,13 @@ impl<'a> CtxType<'a> { let global_array_ptr = cache_builder .build_load(globals_array_ptr_ptr, "global_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + field_name, + globals_array_ptr_ptr.as_instruction_value().unwrap(), + None, + ); let const_index = intrinsics.i32_ty.const_int(index, false); let global_ptr_ptr = unsafe { cache_builder.build_in_bounds_gep( @@ -964,6 +1051,13 @@ impl<'a> CtxType<'a> { let global_ptr = cache_builder .build_load(global_ptr_ptr, "global_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "global_ptr", + globals_array_ptr_ptr.as_instruction_value().unwrap(), + Some(index as u32), + ); let global_ptr_typed = cache_builder.build_pointer_cast(global_ptr, llvm_ptr_ty, "global_ptr_typed"); @@ -973,9 +1067,15 @@ impl<'a> CtxType<'a> { ptr_to_value: global_ptr_typed, } } else { - GlobalCache::Const { - value: cache_builder.build_load(global_ptr_typed, "global_value"), - } + let value = cache_builder.build_load(global_ptr_typed, "global_value"); + tbaa_label( + module.clone(), + intrinsics, + "global", + value.as_instruction_value().unwrap(), + Some(index as u32), + ); + GlobalCache::Const { value } } }) } @@ -984,6 +1084,7 @@ impl<'a> CtxType<'a> { &mut self, index: ImportedFuncIndex, intrinsics: &Intrinsics, + module: Rc>, ) -> (PointerValue, PointerValue) { let (cached_imported_functions, ctx_ptr_value, cache_builder) = ( &mut self.cached_imported_functions, @@ -1002,6 +1103,13 @@ impl<'a> CtxType<'a> { let func_array_ptr = cache_builder .build_load(func_array_ptr_ptr, "func_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_imported_funcs", + func_array_ptr.as_instruction_value().unwrap(), + None, + ); let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false); let imported_func_ptr = unsafe { cache_builder.build_in_bounds_gep( @@ -1023,6 +1131,20 @@ impl<'a> CtxType<'a> { let ctx_ptr = cache_builder .build_load(ctx_ptr_ptr, "ctx_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "imported_func_ptr", + func_ptr.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); + tbaa_label( + module.clone(), + intrinsics, + "imported_func_ctx_ptr", + ctx_ptr.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); ImportedFuncCache { func_ptr, ctx_ptr } }); @@ -1034,6 +1156,7 @@ impl<'a> CtxType<'a> { &mut self, index: usize, intrinsics: &Intrinsics, + module: Rc>, builder: &Builder, ) -> PointerValue { assert!(index < INTERNALS_SIZE); @@ -1048,6 +1171,13 @@ impl<'a> CtxType<'a> { let local_internals_ptr = builder .build_load(local_internals_ptr_ptr, "local_internals_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_internals", + local_internals_ptr_ptr.as_instruction_value().unwrap(), + None, + ); unsafe { builder.build_in_bounds_gep( local_internals_ptr, @@ -1057,3 +1187,83 @@ impl<'a> CtxType<'a> { } } } + +// Given an instruction that operates on memory, mark the access as not aliasing +// other memory accesses which have a different (label, index) pair. +pub fn tbaa_label( + module: Rc>, + intrinsics: &Intrinsics, + label: &str, + instruction: InstructionValue, + index: Option, +) { + // To convey to LLVM that two pointers must be pointing to distinct memory, + // we use LLVM's Type Based Aliasing Analysis, or TBAA, to mark the memory + // operations as having different types whose pointers may not alias. + // + // See the LLVM documentation at + // https://llvm.org/docs/LangRef.html#tbaa-metadata + // + // LLVM TBAA supports many features, but we use it in a simple way, with + // only scalar types that are children of the root node. Every TBAA type we + // declare is NoAlias with the others. See NoAlias, PartialAlias, + // MayAlias and MustAlias in the LLVM documentation: + // https://llvm.org/docs/AliasAnalysis.html#must-may-and-no-alias-responses + + let module = module.borrow_mut(); + let context = module.get_context(); + + // `!wasmer_tbaa_root = {}`, the TBAA root node for wasmer. + let tbaa_root = module + .get_global_metadata("wasmer_tbaa_root") + .pop() + .unwrap_or_else(|| { + module.add_global_metadata("wasmer_tbaa_root", &context.metadata_node(&[])); + module.get_global_metadata("wasmer_tbaa_root")[0] + }); + + // Construct (or look up) the type descriptor, for example + // `!"local 0" = !{!"local 0", !wasmer_tbaa_root}`. + let label = if let Some(idx) = index { + format!("{}{}", label, idx) + } else { + label.to_string() + }; + let type_label = context.metadata_string(label.as_str()); + let type_tbaa = module + .get_global_metadata(label.as_str()) + .pop() + .unwrap_or_else(|| { + module.add_global_metadata( + label.as_str(), + &context.metadata_node(&[type_label.into(), tbaa_root.into()]), + ); + module.get_global_metadata(label.as_str())[0] + }); + + // Construct (or look up) the access tag, which is a struct of the form + // (base type, access type, offset). + // + // "If BaseTy is a scalar type, Offset must be 0 and BaseTy and AccessTy + // must be the same". + // -- https://llvm.org/docs/LangRef.html#tbaa-metadata + let label = label + "_memop"; + let type_tbaa = module + .get_global_metadata(label.as_str()) + .pop() + .unwrap_or_else(|| { + module.add_global_metadata( + label.as_str(), + &context.metadata_node(&[ + type_tbaa.into(), + type_tbaa.into(), + intrinsics.i64_zero.into(), + ]), + ); + module.get_global_metadata(label.as_str())[0] + }); + + // Attach the access tag to the instruction. + let tbaa_kind = context.get_kind_id("tbaa"); + instruction.set_metadata(type_tbaa, tbaa_kind); +} diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 20f915ebc..0d46dc5c0 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -67,9 +67,29 @@ impl ControlFrame { } } +#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] +pub enum ExtraInfo { + None, + + // This values is required to be arithmetic 32-bit NaN (or 32x4) by the WAsm + // machine, but which might not be in the LLVM value. The conversion to + // arithmetic NaN is pending. It is required for correctness. + PendingF32NaN, + + // This values is required to be arithmetic 64-bit NaN (or 64x2) by the WAsm + // machine, but which might not be in the LLVM value. The conversion to + // arithmetic NaN is pending. It is required for correctness. + PendingF64NaN, +} +impl Default for ExtraInfo { + fn default() -> Self { + ExtraInfo::None + } +} + #[derive(Debug)] pub struct State { - pub stack: Vec, + pub stack: Vec<(BasicValueEnum, ExtraInfo)>, control_stack: Vec, value_counter: Cell, @@ -145,10 +165,18 @@ impl State { } pub fn push1(&mut self, value: T) { - self.stack.push(value.as_basic_value_enum()) + self.push1_extra(value, ExtraInfo::None); + } + + pub fn push1_extra(&mut self, value: T, info: ExtraInfo) { + self.stack.push((value.as_basic_value_enum(), info)); } pub fn pop1(&mut self) -> Result { + Ok(self.pop1_extra()?.0) + } + + pub fn pop1_extra(&mut self) -> Result<(BasicValueEnum, ExtraInfo), BinaryReaderError> { self.stack.pop().ok_or(BinaryReaderError { message: "invalid value stack", offset: -1isize as usize, @@ -161,6 +189,14 @@ impl State { Ok((v1, v2)) } + pub fn pop2_extra( + &mut self, + ) -> Result<((BasicValueEnum, ExtraInfo), (BasicValueEnum, ExtraInfo)), BinaryReaderError> { + let v2 = self.pop1_extra()?; + let v1 = self.pop1_extra()?; + Ok((v1, v2)) + } + pub fn pop3( &mut self, ) -> Result<(BasicValueEnum, BasicValueEnum, BasicValueEnum), BinaryReaderError> { @@ -170,7 +206,23 @@ impl State { Ok((v1, v2, v3)) } - pub fn peek1(&self) -> Result { + pub fn pop3_extra( + &mut self, + ) -> Result< + ( + (BasicValueEnum, ExtraInfo), + (BasicValueEnum, ExtraInfo), + (BasicValueEnum, ExtraInfo), + ), + BinaryReaderError, + > { + let v3 = self.pop1_extra()?; + let v2 = self.pop1_extra()?; + let v1 = self.pop1_extra()?; + Ok((v1, v2, v3)) + } + + pub fn peek1_extra(&self) -> Result<(BasicValueEnum, ExtraInfo), BinaryReaderError> { self.stack .get(self.stack.len() - 1) .ok_or(BinaryReaderError { @@ -180,7 +232,14 @@ impl State { .map(|v| *v) } - pub fn peekn(&self, n: usize) -> Result<&[BasicValueEnum], BinaryReaderError> { + pub fn peekn(&self, n: usize) -> Result, BinaryReaderError> { + Ok(self.peekn_extra(n)?.iter().map(|x| x.0).collect()) + } + + pub fn peekn_extra( + &self, + n: usize, + ) -> Result<&[(BasicValueEnum, ExtraInfo)], BinaryReaderError> { self.stack .get(self.stack.len() - n..) .ok_or(BinaryReaderError { @@ -189,8 +248,11 @@ impl State { }) } - pub fn popn_save(&mut self, n: usize) -> Result, BinaryReaderError> { - let v = self.peekn(n)?.to_vec(); + pub fn popn_save_extra( + &mut self, + n: usize, + ) -> Result, BinaryReaderError> { + let v = self.peekn_extra(n)?.to_vec(); self.popn(n)?; Ok(v) } diff --git a/lib/middleware-common-tests/Cargo.toml b/lib/middleware-common-tests/Cargo.toml index 48a5c68bd..e27bb4a9c 100644 --- a/lib/middleware-common-tests/Cargo.toml +++ b/lib/middleware-common-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-middleware-common-tests" -version = "0.8.0" +version = "0.9.0" authors = ["The Wasmer Engineering Team "] edition = "2018" repository = "https://github.com/wasmerio/wasmer" @@ -8,11 +8,11 @@ license = "MIT" publish = false [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmer-middleware-common = { path = "../middleware-common", version = "0.8.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.8.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.8.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-middleware-common = { path = "../middleware-common", version = "0.9.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.9.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } [features] clif = [] diff --git a/lib/middleware-common/Cargo.toml b/lib/middleware-common/Cargo.toml index 0da56b81d..3d4def870 100644 --- a/lib/middleware-common/Cargo.toml +++ b/lib/middleware-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-middleware-common" -version = "0.8.0" +version = "0.9.0" repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime common middlewares" license = "MIT" @@ -8,4 +8,4 @@ authors = ["The Wasmer Engineering Team "] edition = "2018" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 5b9bc2634..8d5dbb614 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime-c-api" -version = "0.8.0" +version = "0.9.0" description = "Wasmer C API library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -17,19 +17,26 @@ libc = "0.2.60" [dependencies.wasmer-runtime] default-features = false path = "../runtime" -version = "0.8.0" +version = "0.9.0" [dependencies.wasmer-runtime-core] default-features = false path = "../runtime-core" -version = "0.8.0" +version = "0.9.0" + +[dependencies.wasmer-wasi] +default-features = false +path = "../wasi" +version = "0.9.0" +optional = true [features] -default = ["cranelift-backend"] +default = ["cranelift-backend", "wasi"] debug = ["wasmer-runtime/debug"] cranelift-backend = ["wasmer-runtime/cranelift", "wasmer-runtime/default-backend-cranelift"] llvm-backend = ["wasmer-runtime/llvm", "wasmer-runtime/default-backend-llvm"] singlepass-backend = ["wasmer-runtime/singlepass", "wasmer-runtime/default-backend-singlepass"] +wasi = ["wasmer-wasi"] [build-dependencies] cbindgen = "0.9" diff --git a/lib/runtime-c-api/README.md b/lib/runtime-c-api/README.md index c652948b8..8ce84a130 100644 --- a/lib/runtime-c-api/README.md +++ b/lib/runtime-c-api/README.md @@ -36,6 +36,7 @@ The C and C++ header files can be found in the source tree of this crate, respectively [`wasmer.h`][wasmer_h] and [`wasmer.hh`][wasmer_hh]. They are automatically generated, and always up-to-date in this repository. +The runtime shared library (so, dll, dylib) can also be downloaded in Wasmer [release page](https://github.com/wasmerio/wasmer/releases). Here is a simple example to use the C API: diff --git a/lib/runtime-c-api/src/export.rs b/lib/runtime-c-api/src/export.rs index d6dfa5d97..40d370111 100644 --- a/lib/runtime-c-api/src/export.rs +++ b/lib/runtime-c-api/src/export.rs @@ -13,7 +13,7 @@ use crate::{ }; use libc::{c_int, c_uint}; use std::{ptr, slice}; -use wasmer_runtime::{Instance, Memory, Module, Value}; +use wasmer_runtime::{Instance, Module, Value}; use wasmer_runtime_core::{export::Export, module::ExportIndex}; /// Intermediate representation of an `Export` instance that is @@ -85,12 +85,41 @@ pub union wasmer_import_export_value { /// List of export/import kinds. #[allow(non_camel_case_types)] #[repr(u32)] -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] +// ================ +// ! DANGER ! +// ================ +// Do not modify these values without updating the `TryFrom` implementation below pub enum wasmer_import_export_kind { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + WASM_FUNCTION = 0, + WASM_GLOBAL = 1, + WASM_MEMORY = 2, + WASM_TABLE = 3, +} + +impl wasmer_import_export_kind { + pub fn to_str(&self) -> &'static str { + match self { + Self::WASM_FUNCTION => "function", + Self::WASM_GLOBAL => "global", + Self::WASM_MEMORY => "memory", + Self::WASM_TABLE => "table", + } + } +} + +impl std::convert::TryFrom for wasmer_import_export_kind { + type Error = (); + + fn try_from(value: u32) -> Result { + Ok(match value { + 0 => Self::WASM_FUNCTION, + 1 => Self::WASM_GLOBAL, + 2 => Self::WASM_MEMORY, + 3 => Self::WASM_TABLE, + _ => return Err(()), + }) + } } /// Gets export descriptors for the given module @@ -355,7 +384,8 @@ pub unsafe extern "C" fn wasmer_export_to_memory( let export = &named_export.export; if let Export::Memory(exported_memory) = export { - *memory = exported_memory as *const Memory as *mut wasmer_memory_t; + let mem = Box::new(exported_memory.clone()); + *memory = Box::into_raw(mem) as *mut wasmer_memory_t; wasmer_result_t::WASMER_OK } else { update_last_error(CApiError { diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import/mod.rs similarity index 56% rename from lib/runtime-c-api/src/import.rs rename to lib/runtime-c-api/src/import/mod.rs index 2d6f9e99d..5b44eb2b5 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import/mod.rs @@ -9,11 +9,11 @@ use crate::{ wasmer_byte_array, wasmer_result_t, }; use libc::c_uint; -use std::{ffi::c_void, ptr, slice, sync::Arc}; +use std::{convert::TryFrom, ffi::c_void, ptr, slice, sync::Arc}; use wasmer_runtime::{Global, Memory, Module, Table}; use wasmer_runtime_core::{ export::{Context, Export, FuncPointer}, - import::ImportObject, + import::{ImportObject, ImportObjectIterator}, module::ImportName, types::{FuncSig, Type}, }; @@ -41,6 +41,10 @@ pub struct wasmer_import_descriptor_t; #[derive(Clone)] pub struct wasmer_import_descriptors_t; +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_import_object_iter_t; + /// Creates a new empty import object. /// See also `wasmer_import_object_append` #[allow(clippy::cast_ptr_alignment)] @@ -51,12 +55,318 @@ pub unsafe extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object Box::into_raw(import_object) as *mut wasmer_import_object_t } +#[cfg(feature = "wasi")] +mod wasi; + +#[cfg(feature = "wasi")] +pub use self::wasi::*; + +/// Gets an entry from an ImportObject at the name and namespace. +/// Stores `name`, `namespace`, and `import_export_value` in `import`. +/// Thus these must remain valid for the lifetime of `import`. +/// +/// The caller owns all data involved. +/// `import_export_value` will be written to based on `tag`. +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_get_import( + import_object: *const wasmer_import_object_t, + namespace: wasmer_byte_array, + name: wasmer_byte_array, + import: *mut wasmer_import_t, + import_export_value: *mut wasmer_import_export_value, + tag: u32, +) -> wasmer_result_t { + let tag: wasmer_import_export_kind = if let Ok(t) = TryFrom::try_from(tag) { + t + } else { + update_last_error(CApiError { + msg: "wasmer_import_export_tag out of range".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject); + let namespace_str = if let Ok(ns) = namespace.as_str() { + ns + } else { + update_last_error(CApiError { + msg: "error converting namespace to UTF-8 string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + let name_str = if let Ok(name) = name.as_str() { + name + } else { + update_last_error(CApiError { + msg: "error converting name to UTF-8 string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + if import.is_null() || import_export_value.is_null() { + update_last_error(CApiError { + msg: "pointers to import and import_export_value must not be null".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + let import_out = &mut *import; + let import_export_value_out = &mut *import_export_value; + if let Some(export) = + import_object.maybe_with_namespace(namespace_str, |ns| ns.get_export(name_str)) + { + match export { + Export::Function { .. } => { + if tag != wasmer_import_export_kind::WASM_FUNCTION { + update_last_error(CApiError { + msg: format!("Found function, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_FUNCTION; + let writer = import_export_value_out.func as *mut Export; + *writer = export.clone(); + } + Export::Memory(memory) => { + if tag != wasmer_import_export_kind::WASM_MEMORY { + update_last_error(CApiError { + msg: format!("Found memory, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_MEMORY; + let writer = import_export_value_out.func as *mut Memory; + *writer = memory.clone(); + } + Export::Table(table) => { + if tag != wasmer_import_export_kind::WASM_TABLE { + update_last_error(CApiError { + msg: format!("Found table, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_TABLE; + let writer = import_export_value_out.func as *mut Table; + *writer = table.clone(); + } + Export::Global(global) => { + if tag != wasmer_import_export_kind::WASM_GLOBAL { + update_last_error(CApiError { + msg: format!("Found global, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_GLOBAL; + let writer = import_export_value_out.func as *mut Global; + *writer = global.clone(); + } + } + + import_out.value = *import_export_value; + import_out.module_name = namespace; + import_out.import_name = name; + + wasmer_result_t::WASMER_OK + } else { + update_last_error(CApiError { + msg: format!("Export {} {} not found", namespace_str, name_str), + }); + wasmer_result_t::WASMER_ERROR + } +} + +/// private wrapper data type used for casting +#[repr(C)] +struct WasmerImportObjectIterator( + std::iter::Peekable::Item>>>, +); + +/// Create an iterator over the functions in the import object. +/// Get the next import with `wasmer_import_object_iter_next` +/// Free the iterator with `wasmer_import_object_iter_destroy` +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_iterate_functions( + import_object: *const wasmer_import_object_t, +) -> *mut wasmer_import_object_iter_t { + if import_object.is_null() { + update_last_error(CApiError { + msg: "import_object must not be null".to_owned(), + }); + return std::ptr::null_mut(); + } + let import_object: &ImportObject = &*(import_object as *const ImportObject); + let iter_inner = Box::new(import_object.clone_ref().into_iter().filter(|(_, _, e)| { + if let Export::Function { .. } = e { + true + } else { + false + } + })) as Box::Item>>; + let iterator = Box::new(WasmerImportObjectIterator(iter_inner.peekable())); + + Box::into_raw(iterator) as *mut wasmer_import_object_iter_t +} + +/// Writes the next value to `import`. `WASMER_ERROR` is returned if there +/// was an error or there's nothing left to return. +/// +/// To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. +/// To check if the iterator is done, use `wasmer_import_object_iter_at_end`. +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_iter_next( + import_object_iter: *mut wasmer_import_object_iter_t, + import: *mut wasmer_import_t, +) -> wasmer_result_t { + if import_object_iter.is_null() || import.is_null() { + update_last_error(CApiError { + msg: "import_object_iter and import must not be null".to_owned(), + }); + return wasmer_result_t::WASMER_ERROR; + } + + let iter = &mut *(import_object_iter as *mut WasmerImportObjectIterator); + let out = &mut *import; + // TODO: the copying here can be optimized away, we just need to use a different type of + // iterator internally + if let Some((namespace, name, export)) = iter.0.next() { + let ns = { + let mut n = namespace.clone(); + n.shrink_to_fit(); + n.into_bytes() + }; + let ns_bytes = wasmer_byte_array { + bytes: ns.as_ptr(), + bytes_len: ns.len() as u32, + }; + + let name = { + let mut n = name.clone(); + n.shrink_to_fit(); + n.into_bytes() + }; + let name_bytes = wasmer_byte_array { + bytes: name.as_ptr(), + bytes_len: name.len() as u32, + }; + + out.module_name = ns_bytes; + out.import_name = name_bytes; + + std::mem::forget(ns); + std::mem::forget(name); + + match export { + Export::Function { .. } => { + let func = Box::new(export.clone()); + + out.tag = wasmer_import_export_kind::WASM_FUNCTION; + out.value = wasmer_import_export_value { + func: Box::into_raw(func) as *mut _ as *const _, + }; + } + Export::Global(global) => { + let glbl = Box::new(global.clone()); + + out.tag = wasmer_import_export_kind::WASM_GLOBAL; + out.value = wasmer_import_export_value { + global: Box::into_raw(glbl) as *mut _ as *const _, + }; + } + Export::Memory(memory) => { + let mem = Box::new(memory.clone()); + + out.tag = wasmer_import_export_kind::WASM_MEMORY; + out.value = wasmer_import_export_value { + memory: Box::into_raw(mem) as *mut _ as *const _, + }; + } + Export::Table(table) => { + let tbl = Box::new(table.clone()); + + out.tag = wasmer_import_export_kind::WASM_TABLE; + out.value = wasmer_import_export_value { + memory: Box::into_raw(tbl) as *mut _ as *const _, + }; + } + } + + wasmer_result_t::WASMER_OK + } else { + wasmer_result_t::WASMER_ERROR + } +} + +/// Returns true if further calls to `wasmer_import_object_iter_next` will +/// not return any new data +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_iter_at_end( + import_object_iter: *mut wasmer_import_object_iter_t, +) -> bool { + if import_object_iter.is_null() { + update_last_error(CApiError { + msg: "import_object_iter must not be null".to_owned(), + }); + return true; + } + let iter = &mut *(import_object_iter as *mut WasmerImportObjectIterator); + + iter.0.peek().is_none() +} + +/// Frees the memory allocated by `wasmer_import_object_iterate_functions` +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_iter_destroy( + import_object_iter: *mut wasmer_import_object_iter_t, +) { + if !import_object_iter.is_null() { + let _ = Box::from_raw(import_object_iter as *mut WasmerImportObjectIterator); + } +} + +/// Frees the memory allocated in `wasmer_import_object_iter_next` +/// +/// This function does not free the memory in `wasmer_import_object_t`; +/// it only frees memory allocated while querying a `wasmer_import_object_t`. +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_imports_destroy( + imports: *mut wasmer_import_t, + imports_len: u32, +) { + if imports.is_null() { + return; + } + let imports: &[wasmer_import_t] = &*slice::from_raw_parts_mut(imports, imports_len as usize); + for import in imports { + let _namespace: Vec = Vec::from_raw_parts( + import.module_name.bytes as *mut u8, + import.module_name.bytes_len as usize, + import.module_name.bytes_len as usize, + ); + let _name: Vec = Vec::from_raw_parts( + import.import_name.bytes as *mut u8, + import.import_name.bytes_len as usize, + import.import_name.bytes_len as usize, + ); + match import.tag { + wasmer_import_export_kind::WASM_FUNCTION => { + let _: Box = Box::from_raw(import.value.func as *mut _); + } + wasmer_import_export_kind::WASM_GLOBAL => { + let _: Box = Box::from_raw(import.value.global as *mut _); + } + wasmer_import_export_kind::WASM_MEMORY => { + let _: Box = Box::from_raw(import.value.memory as *mut _); + } + wasmer_import_export_kind::WASM_TABLE => { + let _: Box = Box::from_raw(import.value.table as *mut _); + } + } + } +} + /// Extends an existing import object with new imports #[allow(clippy::cast_ptr_alignment)] #[no_mangle] pub unsafe extern "C" fn wasmer_import_object_extend( import_object: *mut wasmer_import_object_t, - imports: *mut wasmer_import_t, + imports: *const wasmer_import_t, imports_len: c_uint, ) -> wasmer_result_t { let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject); diff --git a/lib/runtime-c-api/src/import/wasi.rs b/lib/runtime-c-api/src/import/wasi.rs new file mode 100644 index 000000000..3df3c7f70 --- /dev/null +++ b/lib/runtime-c-api/src/import/wasi.rs @@ -0,0 +1,101 @@ +use super::*; +use crate::get_slice_checked; +use std::path::PathBuf; + +/// Opens a directory that's visible to the WASI module as `alias` but +/// is backed by the host file at `host_file_path` +#[repr(C)] +pub struct wasmer_wasi_map_dir_entry_t { + /// What the WASI module will see in its virtual root + pub alias: wasmer_byte_array, + /// The backing file that the WASI module will interact with via the alias + pub host_file_path: wasmer_byte_array, +} + +impl wasmer_wasi_map_dir_entry_t { + /// Converts the data into owned, Rust types + pub unsafe fn as_tuple(&self) -> Result<(String, PathBuf), std::str::Utf8Error> { + let alias = self.alias.as_str()?.to_owned(); + let host_path = std::path::PathBuf::from(self.host_file_path.as_str()?); + + Ok((alias, host_path)) + } +} + +/// Creates a WASI import object. +/// +/// This function treats null pointers as empty collections. +/// For example, passing null for a string in `args`, will lead to a zero +/// length argument in that position. +#[no_mangle] +pub unsafe extern "C" fn wasmer_wasi_generate_import_object( + args: *const wasmer_byte_array, + args_len: c_uint, + envs: *const wasmer_byte_array, + envs_len: c_uint, + preopened_files: *const wasmer_byte_array, + preopened_files_len: c_uint, + mapped_dirs: *const wasmer_wasi_map_dir_entry_t, + mapped_dirs_len: c_uint, +) -> *mut wasmer_import_object_t { + let arg_list = get_slice_checked(args, args_len as usize); + let env_list = get_slice_checked(envs, envs_len as usize); + let preopened_file_list = get_slice_checked(preopened_files, preopened_files_len as usize); + let mapped_dir_list = get_slice_checked(mapped_dirs, mapped_dirs_len as usize); + + wasmer_wasi_generate_import_object_inner( + arg_list, + env_list, + preopened_file_list, + mapped_dir_list, + ) + .unwrap_or(std::ptr::null_mut()) +} + +/// Inner function that wraps error handling +fn wasmer_wasi_generate_import_object_inner( + arg_list: &[wasmer_byte_array], + env_list: &[wasmer_byte_array], + preopened_file_list: &[wasmer_byte_array], + mapped_dir_list: &[wasmer_wasi_map_dir_entry_t], +) -> Result<*mut wasmer_import_object_t, std::str::Utf8Error> { + let arg_vec = arg_list.iter().map(|arg| unsafe { arg.as_vec() }).collect(); + let env_vec = env_list + .iter() + .map(|env_var| unsafe { env_var.as_vec() }) + .collect(); + let po_file_vec = preopened_file_list + .iter() + .map(|po_file| Ok(unsafe { PathBuf::from(po_file.as_str()?) }.to_owned())) + .collect::, _>>()?; + let mapped_dir_vec = mapped_dir_list + .iter() + .map(|entry| unsafe { entry.as_tuple() }) + .collect::, _>>()?; + + let import_object = Box::new(wasmer_wasi::generate_import_object( + arg_vec, + env_vec, + po_file_vec, + mapped_dir_vec, + )); + Ok(Box::into_raw(import_object) as *mut wasmer_import_object_t) +} + +/// Convenience function that creates a WASI import object with no arguments, +/// environment variables, preopened files, or mapped directories. +/// +/// This function is the same as calling [`wasmer_wasi_generate_import_object`] with all +/// empty values. +#[no_mangle] +pub unsafe extern "C" fn wasmer_wasi_generate_default_import_object() -> *mut wasmer_import_object_t +{ + let import_object = Box::new(wasmer_wasi::generate_import_object( + vec![], + vec![], + vec![], + vec![], + )); + + Box::into_raw(import_object) as *mut wasmer_import_object_t +} diff --git a/lib/runtime-c-api/src/instance.rs b/lib/runtime-c-api/src/instance.rs index 69fa0131a..b39e52d7e 100644 --- a/lib/runtime-c-api/src/instance.rs +++ b/lib/runtime-c-api/src/instance.rs @@ -75,6 +75,7 @@ pub unsafe extern "C" fn wasmer_instantiate( let namespace = namespaces.entry(module_name).or_insert_with(Namespace::new); + // TODO check that tag is actually in bounds here let export = match import.tag { wasmer_import_export_kind::WASM_MEMORY => { let mem = import.value.memory as *mut Memory; diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 4dae18cd5..17e96a4c3 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -129,3 +129,34 @@ pub struct wasmer_byte_array { pub bytes: *const u8, pub bytes_len: u32, } + +impl wasmer_byte_array { + /// Get the data as a slice + pub unsafe fn as_slice<'a>(&self) -> &'a [u8] { + get_slice_checked(self.bytes, self.bytes_len as usize) + } + + /// Copy the data into an owned Vec + pub unsafe fn as_vec(&self) -> Vec { + let mut out = Vec::with_capacity(self.bytes_len as usize); + out.extend_from_slice(self.as_slice()); + + out + } + + /// Read the data as a &str, returns an error if the string is not valid UTF8 + pub unsafe fn as_str<'a>(&self) -> Result<&'a str, std::str::Utf8Error> { + std::str::from_utf8(self.as_slice()) + } +} + +/// Gets a slice from a pointer and a length, returning an empty slice if the +/// pointer is null +#[inline] +pub(crate) unsafe fn get_slice_checked<'a, T>(ptr: *const T, len: usize) -> &'a [T] { + if ptr.is_null() { + &[] + } else { + std::slice::from_raw_parts(ptr, len) + } +} diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 26a85acee..b64fa610c 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -25,3 +25,5 @@ test-tables test-validate test-context test-module-import-instantiate +test-wasi-import-object + diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index 7db3cbcb0..d8f206c49 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -6,6 +6,8 @@ add_executable(test-exports test-exports.c) add_executable(test-globals test-globals.c) add_executable(test-import-function test-import-function.c) add_executable(test-imports test-imports.c) +add_executable(test-import-object test-import-object.c) +add_executable(test-wasi-import-object test-wasi-import-object.c) add_executable(test-instantiate test-instantiate.c) add_executable(test-memory test-memory.c) add_executable(test-module test-module.c) @@ -58,6 +60,14 @@ target_link_libraries(test-imports general ${WASMER_LIB}) target_compile_options(test-imports PRIVATE ${COMPILER_OPTIONS}) add_test(test-imports test-imports) +target_link_libraries(test-import-object general ${WASMER_LIB}) +target_compile_options(test-import-object PRIVATE ${COMPILER_OPTIONS}) +add_test(test-import-object test-import-object) + +target_link_libraries(test-wasi-import-object general ${WASMER_LIB}) +target_compile_options(test-wasi-import-object PRIVATE ${COMPILER_OPTIONS}) +add_test(test-wasi-import-object test-wasi-import-object) + target_link_libraries(test-instantiate general ${WASMER_LIB}) target_compile_options(test-instantiate PRIVATE ${COMPILER_OPTIONS}) add_test(test-instantiate test-instantiate) diff --git a/lib/runtime-c-api/tests/assets/README.md b/lib/runtime-c-api/tests/assets/README.md new file mode 100644 index 000000000..52e92c052 --- /dev/null +++ b/lib/runtime-c-api/tests/assets/README.md @@ -0,0 +1,3 @@ +These are used in tests in the parent directory. + +To keep the generated wasm small, use `wasm-opt` and `wasm-strip` from wabt-tools (can be installed via wapm). Addtionally, consider passing the `-C opt-level=z` flag to `rustc` to optimize for size. diff --git a/lib/runtime-c-api/tests/assets/extended_wasi.rs b/lib/runtime-c-api/tests/assets/extended_wasi.rs new file mode 100644 index 000000000..31c659f8e --- /dev/null +++ b/lib/runtime-c-api/tests/assets/extended_wasi.rs @@ -0,0 +1,31 @@ +extern "C" { + fn host_print(ptr: u32, len: u32); +} + +fn main() { + let args = std::env::args().collect::>(); + + println!("Found {} args on program {}", args.len(), args[0]); + + let env_vars = std::env::vars() + .map(|(arg, val)| format!("{}={}", arg, val)) + .collect::>(); + let env_var_list = env_vars.join(", "); + + println!("Found {} env vars: {}", env_vars.len(), env_var_list); + + let dirs_in_root = std::fs::read_dir("/") + .unwrap() + .map(|e| e.map(|inner| format!("{:?}", inner))) + .collect::, _>>() + .unwrap(); + + println!( + "Found {} pre opened dirs: {}", + dirs_in_root.len(), + dirs_in_root.join(", ") + ); + + const HOST_STR: &str = "This string came from a WASI module"; + unsafe { host_print(HOST_STR.as_ptr() as u32, HOST_STR.len() as u32) }; +} diff --git a/lib/runtime-c-api/tests/assets/extended_wasi.wasm b/lib/runtime-c-api/tests/assets/extended_wasi.wasm new file mode 100755 index 000000000..b8eedd722 Binary files /dev/null and b/lib/runtime-c-api/tests/assets/extended_wasi.wasm differ diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c index 893174908..e245414be 100644 --- a/lib/runtime-c-api/tests/test-exports.c +++ b/lib/runtime-c-api/tests/test-exports.c @@ -1,3 +1,4 @@ +#include #include #include "../wasmer.h" #include @@ -242,7 +243,7 @@ int main() wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); - printf("Result: %ld\n", outputs[0].value.I64); + printf("Result: %" PRId64 "\n", outputs[0].value.I64); assert(outputs[0].value.I64 == 7); assert(call_result == WASMER_OK); diff --git a/lib/runtime-c-api/tests/test-import-object b/lib/runtime-c-api/tests/test-import-object new file mode 100755 index 000000000..42e1496de Binary files /dev/null and b/lib/runtime-c-api/tests/test-import-object differ diff --git a/lib/runtime-c-api/tests/test-import-object.c b/lib/runtime-c-api/tests/test-import-object.c new file mode 100644 index 000000000..640f16640 --- /dev/null +++ b/lib/runtime-c-api/tests/test-import-object.c @@ -0,0 +1,172 @@ +#include +#include "../wasmer.h" +#include +#include +#include + +bool static print_str_called = false; + +// Host function that will be imported into the Web Assembly Instance +void print_str(const wasmer_instance_context_t *ctx, int32_t ptr, int32_t len) +{ + print_str_called = true; + const wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); + uint32_t mem_len = wasmer_memory_length(memory); + uint8_t *mem_bytes = wasmer_memory_data(memory); + printf("%.*s", len, mem_bytes + ptr); +} + +// Use the last_error API to retrieve error messages +void print_wasmer_error() +{ + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); +} + +int main() +{ + // Create a new func to hold the parameter and signature + // of our `print_str` host function + wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; + wasmer_value_tag returns_sig[] = {}; + wasmer_import_func_t *func = wasmer_import_func_new((void (*)(void *)) print_str, params_sig, 2, returns_sig, 0); + + // Create module name for our imports + // represented in bytes for UTF-8 compatability + const char *module_name = "env"; + wasmer_byte_array module_name_bytes; + module_name_bytes.bytes = (const uint8_t *) module_name; + module_name_bytes.bytes_len = strlen(module_name); + + // Define a function import + const char *import_name = "_print_str"; + wasmer_byte_array import_name_bytes; + import_name_bytes.bytes = (const uint8_t *) import_name; + import_name_bytes.bytes_len = strlen(import_name); + wasmer_import_t func_import; + func_import.module_name = module_name_bytes; + func_import.import_name = import_name_bytes; + func_import.tag = WASM_FUNCTION; + func_import.value.func = func; + + // Define a memory import + const char *import_memory_name = "memory"; + wasmer_byte_array import_memory_name_bytes; + import_memory_name_bytes.bytes = (const uint8_t *) import_memory_name; + import_memory_name_bytes.bytes_len = strlen(import_memory_name); + wasmer_import_t memory_import; + memory_import.module_name = module_name_bytes; + memory_import.import_name = import_memory_name_bytes; + memory_import.tag = WASM_MEMORY; + wasmer_memory_t *memory = NULL; + wasmer_limits_t descriptor; + descriptor.min = 256; + wasmer_limit_option_t max; + max.has_some = true; + max.some = 256; + descriptor.max = max; + wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor); + if (memory_result != WASMER_OK) + { + print_wasmer_error(); + } + memory_import.value.memory = memory; + + // Define a global import + const char *import_global_name = "__memory_base"; + wasmer_byte_array import_global_name_bytes; + import_global_name_bytes.bytes = (const uint8_t *) import_global_name; + import_global_name_bytes.bytes_len = strlen(import_global_name); + wasmer_import_t global_import; + global_import.module_name = module_name_bytes; + global_import.import_name = import_global_name_bytes; + global_import.tag = WASM_GLOBAL; + wasmer_value_t val; + val.tag = WASM_I32; + val.value.I32 = 1024; + wasmer_global_t *global = wasmer_global_new(val, false); + global_import.value.global = global; + + // Define a table import + const char *import_table_name = "table"; + wasmer_byte_array import_table_name_bytes; + import_table_name_bytes.bytes = (const uint8_t *) import_table_name; + import_table_name_bytes.bytes_len = strlen(import_table_name); + wasmer_import_t table_import; + table_import.module_name = module_name_bytes; + table_import.import_name = import_table_name_bytes; + table_import.tag = WASM_TABLE; + wasmer_table_t *table = NULL; + wasmer_limits_t table_descriptor; + table_descriptor.min = 256; + wasmer_limit_option_t table_max; + table_max.has_some = true; + table_max.some = 256; + table_descriptor.max = table_max; + wasmer_result_t table_result = wasmer_table_new(&table, table_descriptor); + if (table_result != WASMER_OK) + { + print_wasmer_error(); + } + table_import.value.table = table; + + // Define an empty import object + wasmer_import_object_t *import_object = wasmer_import_object_new(); + // Create our imports + wasmer_import_t imports[] = {func_import, global_import, memory_import, table_import}; + int imports_len = sizeof(imports) / sizeof(imports[0]); + // Add our imports to the import object + wasmer_import_object_extend(import_object, imports, imports_len); + + // Read the wasm file bytes + FILE *file = fopen("assets/hello_wasm.wasm", "r"); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + wasmer_module_t *module = NULL; + // Compile the WebAssembly module + wasmer_result_t compile_result = wasmer_compile(&module, bytes, len); + printf("Compile result: %d\n", compile_result); + if (compile_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(compile_result == WASMER_OK); + + // Instantiatoe the module with our import_object + wasmer_instance_t *instance = NULL; + wasmer_result_t instantiate_result = wasmer_module_import_instantiate(&instance, module, import_object); + printf("Instantiate result: %d\n", instantiate_result); + if (instantiate_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(instantiate_result == WASMER_OK); + + // Call the exported "hello_wasm" function of our instance + wasmer_value_t params[] = {}; + wasmer_value_t result_one; + wasmer_value_t results[] = {result_one}; + wasmer_result_t call_result = wasmer_instance_call(instance, "_hello_wasm", params, 0, results, 1); + printf("Call result: %d\n", call_result); + assert(call_result == WASMER_OK); + assert(print_str_called); + + // Use *_destroy methods to cleanup as specified in the header documentation + wasmer_import_func_destroy(func); + wasmer_global_destroy(global); + wasmer_memory_destroy(memory); + wasmer_table_destroy(table); + wasmer_instance_destroy(instance); + wasmer_import_object_destroy(import_object); + wasmer_module_destroy(module); + + return 0; +} diff --git a/lib/runtime-c-api/tests/test-wasi-import-object b/lib/runtime-c-api/tests/test-wasi-import-object new file mode 100755 index 000000000..912bc8c0d Binary files /dev/null and b/lib/runtime-c-api/tests/test-wasi-import-object differ diff --git a/lib/runtime-c-api/tests/test-wasi-import-object.c b/lib/runtime-c-api/tests/test-wasi-import-object.c new file mode 100644 index 000000000..bd1478dc1 --- /dev/null +++ b/lib/runtime-c-api/tests/test-wasi-import-object.c @@ -0,0 +1,250 @@ +#include +#include "../wasmer.h" +#include +#include +#include + +static bool host_print_called = false; + +// Host function that will be imported into the Web Assembly Instance +void host_print(const wasmer_instance_context_t *ctx, int32_t ptr, int32_t len) +{ + host_print_called = true; + const wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); + uint32_t mem_len = wasmer_memory_length(memory); + uint8_t *mem_bytes = wasmer_memory_data(memory); + printf("%.*s", len, mem_bytes + ptr); +} + +// Use the last_error API to retrieve error messages +void print_wasmer_error() +{ + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); +} + +// helper function to print byte array to stdout +void print_byte_array(wasmer_byte_array *arr) { + for (int i = 0; i < arr->bytes_len; ++i) { + putchar(arr->bytes[i]); + } +} + +int main() +{ + // Create a new func to hold the parameter and signature + // of our `host_print` host function + wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; + wasmer_value_tag returns_sig[] = {}; + wasmer_import_func_t *func = wasmer_import_func_new((void (*)(void *)) host_print, params_sig, 2, returns_sig, 0); + + // Create module name for our imports + // represented in bytes for UTF-8 compatability + const char *module_name = "env"; + wasmer_byte_array module_name_bytes; + module_name_bytes.bytes = (const uint8_t *) module_name; + module_name_bytes.bytes_len = strlen(module_name); + + // Define a function import + const char *import_name = "host_print"; + wasmer_byte_array import_name_bytes; + import_name_bytes.bytes = (const uint8_t *) import_name; + import_name_bytes.bytes_len = strlen(import_name); + wasmer_import_t func_import; + func_import.module_name = module_name_bytes; + func_import.import_name = import_name_bytes; + func_import.tag = WASM_FUNCTION; + func_import.value.func = func; + + // Define a memory import + const char *import_memory_name = "memory"; + wasmer_byte_array import_memory_name_bytes; + import_memory_name_bytes.bytes = (const uint8_t *) import_memory_name; + import_memory_name_bytes.bytes_len = strlen(import_memory_name); + wasmer_import_t memory_import; + memory_import.module_name = module_name_bytes; + memory_import.import_name = import_memory_name_bytes; + memory_import.tag = WASM_MEMORY; + wasmer_memory_t *memory = NULL; + wasmer_limits_t descriptor; + descriptor.min = 256; + wasmer_limit_option_t max; + max.has_some = true; + max.some = 256; + descriptor.max = max; + wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor); + if (memory_result != WASMER_OK) + { + print_wasmer_error(); + } + memory_import.value.memory = memory; + + // Define a global import + const char *import_global_name = "__memory_base"; + wasmer_byte_array import_global_name_bytes; + import_global_name_bytes.bytes = (const uint8_t *) import_global_name; + import_global_name_bytes.bytes_len = strlen(import_global_name); + wasmer_import_t global_import; + global_import.module_name = module_name_bytes; + global_import.import_name = import_global_name_bytes; + global_import.tag = WASM_GLOBAL; + wasmer_value_t val; + val.tag = WASM_I32; + val.value.I32 = 1024; + wasmer_global_t *global = wasmer_global_new(val, false); + global_import.value.global = global; + + // Define a table import + const char *import_table_name = "table"; + wasmer_byte_array import_table_name_bytes; + import_table_name_bytes.bytes = (const uint8_t *) import_table_name; + import_table_name_bytes.bytes_len = strlen(import_table_name); + wasmer_import_t table_import; + table_import.module_name = module_name_bytes; + table_import.import_name = import_table_name_bytes; + table_import.tag = WASM_TABLE; + wasmer_table_t *table = NULL; + wasmer_limits_t table_descriptor; + table_descriptor.min = 256; + wasmer_limit_option_t table_max; + table_max.has_some = true; + table_max.some = 256; + table_descriptor.max = table_max; + wasmer_result_t table_result = wasmer_table_new(&table, table_descriptor); + if (table_result != WASMER_OK) + { + print_wasmer_error(); + } + table_import.value.table = table; + + + // Create arbitrary arguments for our program + + // Set up data for our WASI import object + // + // Environment variables and program arguments are processed by the WASI + // program. They will not have any effects unless the program includes + // logic to process them. + const char *wasi_prog_name = "wasi_test_program"; + const char *wasi_first_arg = "--help"; + wasmer_byte_array args[] = { + { .bytes = (const uint8_t *) wasi_prog_name, + .bytes_len = strlen(wasi_prog_name) }, + { .bytes = (const uint8_t *) wasi_first_arg, + .bytes_len = strlen(wasi_first_arg) } + }; + int wasi_argc = sizeof(args) / sizeof(args[0]); + + // Create arbitrary environment variables for our program; + const char *wasi_color_env = "COLOR=TRUE"; + const char *wasi_app_should_log = "APP_SHOULD_LOG=FALSE"; + wasmer_byte_array envs[] = { + { .bytes = (const uint8_t *) wasi_color_env, + .bytes_len = strlen(wasi_color_env) }, + { .bytes = (const uint8_t *) wasi_app_should_log, + .bytes_len = strlen(wasi_app_should_log) } + }; + int wasi_env_len = sizeof(args) / sizeof(args[0]); + + // Open the host's current directory under a different name. + // WARNING: this gives the WASI module limited access to your host's file system, + // use caution when granting these permissions to untrusted Wasm modules. + const char *wasi_map_dir_alias = "the_host_current_dir"; + const char *wasi_map_dir_host_path = "."; + wasmer_wasi_map_dir_entry_t mapped_dirs[] = { + { .alias = + { .bytes = (const uint8_t *) wasi_map_dir_alias, + .bytes_len = strlen(wasi_map_dir_alias) }, + .host_file_path = + { .bytes = (const uint8_t *) wasi_map_dir_host_path, + .bytes_len = strlen(wasi_map_dir_host_path) } } + }; + int mapped_dir_len = sizeof(mapped_dirs) / sizeof(mapped_dirs[0]); + + // Create the WASI import object + wasmer_import_object_t *import_object = + wasmer_wasi_generate_import_object(args, wasi_argc, + envs, wasi_env_len, + NULL, 0, + mapped_dirs, mapped_dir_len); + + // Create our imports + wasmer_import_t imports[] = {func_import, global_import, memory_import, table_import}; + int imports_len = sizeof(imports) / sizeof(imports[0]); + // Add our imports to the import object + wasmer_import_object_extend(import_object, imports, imports_len); + + // Read the wasm file bytes + FILE *file = fopen("assets/extended_wasi.wasm", "r"); + assert(file); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + wasmer_module_t *module = NULL; + // Compile the WebAssembly module + wasmer_result_t compile_result = wasmer_compile(&module, bytes, len); + printf("Compile result: %d\n", compile_result); + if (compile_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(compile_result == WASMER_OK); + + // Instantiatoe the module with our import_object + wasmer_instance_t *instance = NULL; + wasmer_result_t instantiate_result = wasmer_module_import_instantiate(&instance, module, import_object); + printf("Instantiate result: %d\n", instantiate_result); + if (instantiate_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(instantiate_result == WASMER_OK); + + // Call the exported "hello_wasm" function of our instance + wasmer_value_t params[] = {}; + wasmer_value_t result_one; + wasmer_value_t results[] = {result_one}; + // _start runs before main for WASI programs + wasmer_result_t call_result = wasmer_instance_call(instance, "_start", params, 0, results, 1); + printf("Call result: %d\n", call_result); + assert(call_result == WASMER_OK); + assert(host_print_called); + + wasmer_import_object_iter_t *func_iter = wasmer_import_object_iterate_functions(import_object); + + puts("Functions in import object:"); + while ( !wasmer_import_object_iter_at_end(func_iter) ) { + wasmer_import_t import; + wasmer_result_t result = wasmer_import_object_iter_next(func_iter, &import); + assert(result == WASMER_OK); + + print_byte_array(&import.module_name); + putchar(' '); + print_byte_array(&import.import_name); + putchar('\n'); + + assert(import.tag == WASM_FUNCTION); + assert(import.value.func); + wasmer_import_object_imports_destroy(&import, 1); + } + wasmer_import_object_iter_destroy(func_iter); + + // Use *_destroy methods to cleanup as specified in the header documentation + wasmer_import_func_destroy(func); + wasmer_global_destroy(global); + wasmer_memory_destroy(memory); + wasmer_table_destroy(table); + wasmer_instance_destroy(instance); + wasmer_import_object_destroy(import_object); + wasmer_module_destroy(module); + + return 0; +} + diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 447d31075..eb9dab50d 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -10,10 +10,10 @@ * List of export/import kinds. */ enum wasmer_import_export_kind { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + WASM_FUNCTION = 0, + WASM_GLOBAL = 1, + WASM_MEMORY = 2, + WASM_TABLE = 3, }; typedef uint32_t wasmer_import_export_kind; @@ -138,6 +138,10 @@ typedef struct { typedef struct { +} wasmer_import_object_iter_t; + +typedef struct { + } wasmer_instance_t; typedef struct { @@ -170,6 +174,21 @@ typedef struct { } wasmer_trampoline_buffer_t; +/** + * Opens a directory that's visible to the WASI module as `alias` but + * is backed by the host file at `host_file_path` + */ +typedef struct { + /** + * What the WASI module will see in its virtual root + */ + wasmer_byte_array alias; + /** + * The backing file that the WASI module will interact with via the alias + */ + wasmer_byte_array host_file_path; +} wasmer_wasi_map_dir_entry_t; + /** * Creates a new Module from the given wasm bytes. * @@ -451,9 +470,60 @@ void wasmer_import_object_destroy(wasmer_import_object_t *import_object); * Extends an existing import object with new imports */ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_object, - wasmer_import_t *imports, + const wasmer_import_t *imports, unsigned int imports_len); +/** + * Gets an entry from an ImportObject at the name and namespace. + * Stores `name`, `namespace`, and `import_export_value` in `import`. + * Thus these must remain valid for the lifetime of `import`. + * + * The caller owns all data involved. + * `import_export_value` will be written to based on `tag`. + */ +wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, + wasmer_byte_array namespace_, + wasmer_byte_array name, + wasmer_import_t *import, + wasmer_import_export_value *import_export_value, + uint32_t tag); + +/** + * Frees the memory allocated in `wasmer_import_object_iter_next` + * + * This function does not free the memory in `wasmer_import_object_t`; + * it only frees memory allocated while querying a `wasmer_import_object_t`. + */ +void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); + +/** + * Returns true if further calls to `wasmer_import_object_iter_next` will + * not return any new data + */ +bool wasmer_import_object_iter_at_end(wasmer_import_object_iter_t *import_object_iter); + +/** + * Frees the memory allocated by `wasmer_import_object_iterate_functions` + */ +void wasmer_import_object_iter_destroy(wasmer_import_object_iter_t *import_object_iter); + +/** + * Writes the next value to `import`. `WASMER_ERROR` is returned if there + * was an error or there's nothing left to return. + * + * To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. + * To check if the iterator is done, use `wasmer_import_object_iter_at_end`. + */ +wasmer_result_t wasmer_import_object_iter_next(wasmer_import_object_iter_t *import_object_iter, + wasmer_import_t *import); + +/** + * Create an iterator over the functions in the import object. + * Get the next import with `wasmer_import_object_iter_next` + * Free the iterator with `wasmer_import_object_iter_destroy` + */ +wasmer_import_object_iter_t *wasmer_import_object_iterate_functions(const wasmer_import_object_t *import_object); + /** * Creates a new empty import object. * See also `wasmer_import_object_append` @@ -756,4 +826,29 @@ void *wasmer_trampoline_get_context(void); */ bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +/** + * Convenience function that creates a WASI import object with no arguments, + * environment variables, preopened files, or mapped directories. + * + * This function is the same as calling [`wasmer_wasi_generate_import_object`] with all + * empty values. + */ +wasmer_import_object_t *wasmer_wasi_generate_default_import_object(void); + +/** + * Creates a WASI import object. + * + * This function treats null pointers as empty collections. + * For example, passing null for a string in `args`, will lead to a zero + * length argument in that position. + */ +wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_array *args, + unsigned int args_len, + const wasmer_byte_array *envs, + unsigned int envs_len, + const wasmer_byte_array *preopened_files, + unsigned int preopened_files_len, + const wasmer_wasi_map_dir_entry_t *mapped_dirs, + unsigned int mapped_dirs_len); + #endif /* WASMER_H */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index d372d8eb3..04a095c48 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -8,10 +8,10 @@ /// List of export/import kinds. enum class wasmer_import_export_kind : uint32_t { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + WASM_FUNCTION = 0, + WASM_GLOBAL = 1, + WASM_MEMORY = 2, + WASM_TABLE = 3, }; enum class wasmer_result_t { @@ -120,6 +120,10 @@ struct wasmer_import_t { wasmer_import_export_value value; }; +struct wasmer_import_object_iter_t { + +}; + struct wasmer_instance_t { }; @@ -154,6 +158,15 @@ struct wasmer_trampoline_buffer_t { }; +/// Opens a directory that's visible to the WASI module as `alias` but +/// is backed by the host file at `host_file_path` +struct wasmer_wasi_map_dir_entry_t { + /// What the WASI module will see in its virtual root + wasmer_byte_array alias; + /// The backing file that the WASI module will interact with via the alias + wasmer_byte_array host_file_path; +}; + extern "C" { /// Creates a new Module from the given wasm bytes. @@ -359,9 +372,48 @@ void wasmer_import_object_destroy(wasmer_import_object_t *import_object); /// Extends an existing import object with new imports wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_object, - wasmer_import_t *imports, + const wasmer_import_t *imports, unsigned int imports_len); +/// Gets an entry from an ImportObject at the name and namespace. +/// Stores `name`, `namespace`, and `import_export_value` in `import`. +/// Thus these must remain valid for the lifetime of `import`. +/// +/// The caller owns all data involved. +/// `import_export_value` will be written to based on `tag`. +wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, + wasmer_byte_array namespace_, + wasmer_byte_array name, + wasmer_import_t *import, + wasmer_import_export_value *import_export_value, + uint32_t tag); + +/// Frees the memory allocated in `wasmer_import_object_iter_next` +/// +/// This function does not free the memory in `wasmer_import_object_t`; +/// it only frees memory allocated while querying a `wasmer_import_object_t`. +void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); + +/// Returns true if further calls to `wasmer_import_object_iter_next` will +/// not return any new data +bool wasmer_import_object_iter_at_end(wasmer_import_object_iter_t *import_object_iter); + +/// Frees the memory allocated by `wasmer_import_object_iterate_functions` +void wasmer_import_object_iter_destroy(wasmer_import_object_iter_t *import_object_iter); + +/// Writes the next value to `import`. `WASMER_ERROR` is returned if there +/// was an error or there's nothing left to return. +/// +/// To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. +/// To check if the iterator is done, use `wasmer_import_object_iter_at_end`. +wasmer_result_t wasmer_import_object_iter_next(wasmer_import_object_iter_t *import_object_iter, + wasmer_import_t *import); + +/// Create an iterator over the functions in the import object. +/// Get the next import with `wasmer_import_object_iter_next` +/// Free the iterator with `wasmer_import_object_iter_destroy` +wasmer_import_object_iter_t *wasmer_import_object_iterate_functions(const wasmer_import_object_t *import_object); + /// Creates a new empty import object. /// See also `wasmer_import_object_append` wasmer_import_object_t *wasmer_import_object_new(); @@ -590,6 +642,27 @@ void *wasmer_trampoline_get_context(); /// Returns true for valid wasm bytes and false for invalid bytes bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +/// Convenience function that creates a WASI import object with no arguments, +/// environment variables, preopened files, or mapped directories. +/// +/// This function is the same as calling [`wasmer_wasi_generate_import_object`] with all +/// empty values. +wasmer_import_object_t *wasmer_wasi_generate_default_import_object(); + +/// Creates a WASI import object. +/// +/// This function treats null pointers as empty collections. +/// For example, passing null for a string in `args`, will lead to a zero +/// length argument in that position. +wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_array *args, + unsigned int args_len, + const wasmer_byte_array *envs, + unsigned int envs_len, + const wasmer_byte_array *preopened_files, + unsigned int preopened_files_len, + const wasmer_wasi_map_dir_entry_t *mapped_dirs, + unsigned int mapped_dirs_len); + } // extern "C" #endif // WASMER_H diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml new file mode 100644 index 000000000..d2db29f2b --- /dev/null +++ b/lib/runtime-core-tests/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "wasmer-runtime-core-tests" +version = "0.9.0" +description = "Tests for the Wasmer runtime core crate" +license = "MIT" +authors = ["The Wasmer Engineering Team "] +edition = "2018" +publish = false + +[dependencies] +wabt = "0.9.1" +wasmer-runtime-core = { path = "../runtime-core", version = "0.9" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.9", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9", optional = true } + +[features] +default = ["backend-cranelift"] +backend-cranelift = ["wasmer-clif-backend"] +backend-singlepass = ["wasmer-singlepass-backend"] +backend-llvm = ["wasmer-llvm-backend"] \ No newline at end of file diff --git a/lib/runtime-core-tests/src/lib.rs b/lib/runtime-core-tests/src/lib.rs new file mode 100644 index 000000000..96f7e6265 --- /dev/null +++ b/lib/runtime-core-tests/src/lib.rs @@ -0,0 +1,21 @@ +pub use wabt::wat2wasm; +use wasmer_runtime_core::backend::Compiler; + +#[cfg(feature = "backend-cranelift")] +pub fn get_compiler() -> impl Compiler { + use wasmer_clif_backend::CraneliftCompiler; + + CraneliftCompiler::new() +} + +#[cfg(feature = "backend-singlepass")] +pub fn get_compiler() -> impl Compiler { + use wasmer_singlepass_backend::SinglePassCompiler; + SinglePassCompiler::new() +} + +#[cfg(feature = "backend-llvm")] +pub fn get_compiler() -> impl Compiler { + use wasmer_llvm_backend::LLVMCompiler; + LLVMCompiler::new() +} diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs new file mode 100644 index 000000000..69b9040cd --- /dev/null +++ b/lib/runtime-core-tests/tests/imports.rs @@ -0,0 +1,137 @@ +use wasmer_runtime_core::{ + compile_with, error::RuntimeError, imports, memory::Memory, typed_func::Func, + types::MemoryDescriptor, units::Pages, vm, +}; +use wasmer_runtime_core_tests::{get_compiler, wat2wasm}; + +#[test] +fn imported_functions_forms() { + const MODULE: &str = r#" +(module + (type $type (func (param i32) (result i32))) + (import "env" "memory" (memory 1 1)) + (import "env" "callback_fn" (func $callback_fn (type $type))) + (import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type))) + (import "env" "callback_fn_trap" (func $callback_fn_trap (type $type))) + (import "env" "callback_fn_trap_with_vmctx" (func $callback_fn_trap_with_vmctx (type $type))) + (func (export "function_fn") (type $type) + get_local 0 + call $callback_fn) + (func (export "function_fn_with_vmctx") (type $type) + get_local 0 + call $callback_fn_with_vmctx) + (func (export "function_fn_trap") (type $type) + get_local 0 + call $callback_fn_trap) + (func (export "function_fn_trap_with_vmctx") (type $type) + get_local 0 + call $callback_fn_trap_with_vmctx)) +"#; + + let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed"); + let module = compile_with(&wasm_binary, &get_compiler()).unwrap(); + let memory_descriptor = MemoryDescriptor::new(Pages(1), Some(Pages(1)), false).unwrap(); + let memory = Memory::new(memory_descriptor).unwrap(); + + const SHIFT: i32 = 10; + memory.view()[0].set(SHIFT); + + let import_object = imports! { + "env" => { + "memory" => memory.clone(), + "callback_fn" => Func::new(callback_fn), + "callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx), + "callback_fn_trap" => Func::new(callback_fn_trap), + "callback_fn_trap_with_vmctx" => Func::new(callback_fn_trap_with_vmctx), + }, + }; + let instance = module.instantiate(&import_object).unwrap(); + + macro_rules! call_and_assert { + ($function:ident, $expected_value:expr) => { + let $function: Func = instance.func(stringify!($function)).unwrap(); + + let result = $function.call(1); + + match (result, $expected_value) { + (Ok(value), expected_value) => assert_eq!( + Ok(value), + expected_value, + concat!("Expected right when calling `", stringify!($function), "`.") + ), + ( + Err(RuntimeError::Error { data }), + Err(RuntimeError::Error { + data: expected_data, + }), + ) => { + if let (Some(data), Some(expected_data)) = ( + data.downcast_ref::<&str>(), + expected_data.downcast_ref::<&str>(), + ) { + assert_eq!( + data, expected_data, + concat!("Expected right when calling `", stringify!($function), "`.") + ) + } else if let (Some(data), Some(expected_data)) = ( + data.downcast_ref::(), + expected_data.downcast_ref::(), + ) { + assert_eq!( + data, expected_data, + concat!("Expected right when calling `", stringify!($function), "`.") + ) + } else { + assert!(false, "Unexpected error, cannot compare it.") + } + } + (result, expected_value) => assert!( + false, + format!( + "Unexpected assertion for `{}`: left = `{:?}`, right = `{:?}`.", + stringify!($function), + result, + expected_value + ) + ), + } + }; + } + + call_and_assert!(function_fn, Ok(2)); + call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT)); + call_and_assert!( + function_fn_trap, + Err(RuntimeError::Error { + data: Box::new(format!("foo {}", 1)) + }) + ); + call_and_assert!( + function_fn_trap_with_vmctx, + Err(RuntimeError::Error { + data: Box::new(format!("baz {}", 2 + SHIFT)) + }) + ); +} + +fn callback_fn(n: i32) -> Result { + Ok(n + 1) +} + +fn callback_fn_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { + let memory = vmctx.memory(0); + let shift: i32 = memory.view()[0].get(); + + Ok(shift + n + 1) +} + +fn callback_fn_trap(n: i32) -> Result { + Err(format!("foo {}", n)) +} + +fn callback_fn_trap_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { + let memory = vmctx.memory(0); + let shift: i32 = memory.view()[0].get(); + + Err(format!("baz {}", shift + n + 1)) +} diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 7fd9e32e8..7e8e80c5f 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime-core" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime core library" license = "MIT" authors = ["The Wasmer Engineering Team "] diff --git a/lib/runtime-core/image-loading-linux-x86-64.s b/lib/runtime-core/image-loading-linux-x86-64.s index 859f010f8..c9d6edff2 100644 --- a/lib/runtime-core/image-loading-linux-x86-64.s +++ b/lib/runtime-core/image-loading-linux-x86-64.s @@ -41,6 +41,30 @@ add $8, %rsp movq (%rsp), %xmm7 add $8, %rsp +movq (%rsp), %xmm8 +add $8, %rsp + +movq (%rsp), %xmm9 +add $8, %rsp + +movq (%rsp), %xmm10 +add $8, %rsp + +movq (%rsp), %xmm11 +add $8, %rsp + +movq (%rsp), %xmm12 +add $8, %rsp + +movq (%rsp), %xmm13 +add $8, %rsp + +movq (%rsp), %xmm14 +add $8, %rsp + +movq (%rsp), %xmm15 +add $8, %rsp + popq %rbp popq %rax popq %rbx diff --git a/lib/runtime-core/image-loading-macos-x86-64.s b/lib/runtime-core/image-loading-macos-x86-64.s index ef6f94510..5e19f7b4a 100644 --- a/lib/runtime-core/image-loading-macos-x86-64.s +++ b/lib/runtime-core/image-loading-macos-x86-64.s @@ -41,6 +41,30 @@ add $8, %rsp movq (%rsp), %xmm7 add $8, %rsp +movq (%rsp), %xmm8 +add $8, %rsp + +movq (%rsp), %xmm9 +add $8, %rsp + +movq (%rsp), %xmm10 +add $8, %rsp + +movq (%rsp), %xmm11 +add $8, %rsp + +movq (%rsp), %xmm12 +add $8, %rsp + +movq (%rsp), %xmm13 +add $8, %rsp + +movq (%rsp), %xmm14 +add $8, %rsp + +movq (%rsp), %xmm15 +add $8, %rsp + popq %rbp popq %rax popq %rbx diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index e69943002..ff21e9195 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -148,7 +148,7 @@ impl LocalBacking { Initializer::Const(Value::I32(offset)) => offset as u32, Initializer::Const(_) => { return Err(vec![LinkError::Generic { - message: "a const initializer must be the i32 type".to_string(), + message: "a const initializer must be an i32".to_string(), }]); } Initializer::GetGlobal(import_global_index) => { @@ -209,7 +209,7 @@ impl LocalBacking { Initializer::Const(Value::I32(offset)) => offset as u32, Initializer::Const(_) => { return Err(vec![LinkError::Generic { - message: "a const initializer must be the i32 type".to_string(), + message: "a const initializer must be an i32".to_string(), }]); } Initializer::GetGlobal(import_global_index) => { @@ -282,7 +282,7 @@ impl LocalBacking { Initializer::Const(Value::I32(offset)) => offset as u32, Initializer::Const(_) => { return Err(vec![LinkError::Generic { - message: "a const initializer must be the i32 type".to_string(), + message: "a const initializer must be an i32".to_string(), }]); } Initializer::GetGlobal(import_global_index) => { @@ -340,7 +340,7 @@ impl LocalBacking { Initializer::Const(Value::I32(offset)) => offset as u32, Initializer::Const(_) => { return Err(vec![LinkError::Generic { - message: "a const initializer must be the i32 type".to_string(), + message: "a const initializer be an i32".to_string(), }]); } Initializer::GetGlobal(import_global_index) => { diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index a1a1f58c2..bc21052fa 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -207,7 +207,7 @@ pub fn allocate_and_run R>(size: usize, f: F) -> R { // NOTE: Keep this consistent with `image-loading-*.s`. stack[end_offset - 4 - 10] = &mut ctx as *mut Context as usize as u64; // rdi - const NUM_SAVED_REGISTERS: usize = 23; + const NUM_SAVED_REGISTERS: usize = 31; let stack_begin = stack .as_mut_ptr() .offset((end_offset - 4 - NUM_SAVED_REGISTERS) as isize); @@ -347,7 +347,7 @@ unsafe fn install_sighandler() { pub struct FaultInfo { pub faulting_addr: *const c_void, pub ip: *const c_void, - pub known_registers: [Option; 24], + pub known_registers: [Option; 32], } #[cfg(all(target_os = "linux", target_arch = "x86_64"))] @@ -378,7 +378,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> let gregs = &(*ucontext).uc_mcontext.gregs; let fpregs = &*(*ucontext).uc_mcontext.fpregs; - let mut known_registers: [Option; 24] = [None; 24]; + let mut known_registers: [Option; 32] = [None; 32]; known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs[REG_R15 as usize] as _); known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs[REG_R14 as usize] as _); known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs[REG_R13 as usize] as _); @@ -405,6 +405,14 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(read_xmm(&fpregs._xmm[5])); known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(read_xmm(&fpregs._xmm[6])); known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(read_xmm(&fpregs._xmm[7])); + known_registers[X64Register::XMM(XMM::XMM8).to_index().0] = Some(read_xmm(&fpregs._xmm[8])); + known_registers[X64Register::XMM(XMM::XMM9).to_index().0] = Some(read_xmm(&fpregs._xmm[9])); + known_registers[X64Register::XMM(XMM::XMM10).to_index().0] = Some(read_xmm(&fpregs._xmm[10])); + known_registers[X64Register::XMM(XMM::XMM11).to_index().0] = Some(read_xmm(&fpregs._xmm[11])); + known_registers[X64Register::XMM(XMM::XMM12).to_index().0] = Some(read_xmm(&fpregs._xmm[12])); + known_registers[X64Register::XMM(XMM::XMM13).to_index().0] = Some(read_xmm(&fpregs._xmm[13])); + known_registers[X64Register::XMM(XMM::XMM14).to_index().0] = Some(read_xmm(&fpregs._xmm[14])); + known_registers[X64Register::XMM(XMM::XMM15).to_index().0] = Some(read_xmm(&fpregs._xmm[15])); FaultInfo { faulting_addr: si_addr as usize as _, @@ -458,8 +466,17 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> } #[repr(C)] struct fpstate { - _unused: [u8; 168], - xmm: [[u64; 2]; 8], + _cwd: u16, + _swd: u16, + _ftw: u16, + _fop: u16, + _rip: u64, + _rdp: u64, + _mxcsr: u32, + _mxcr_mask: u32, + _st: [[u16; 8]; 8], + xmm: [[u64; 2]; 16], + _padding: [u32; 24], } #[allow(dead_code)] #[repr(C)] @@ -476,7 +493,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> let ss = &(*(*ucontext).uc_mcontext).ss; let fs = &(*(*ucontext).uc_mcontext).fs; - let mut known_registers: [Option; 24] = [None; 24]; + let mut known_registers: [Option; 32] = [None; 32]; known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(ss.r15); known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(ss.r14); @@ -504,6 +521,14 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(fs.xmm[5][0]); known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(fs.xmm[6][0]); known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(fs.xmm[7][0]); + known_registers[X64Register::XMM(XMM::XMM8).to_index().0] = Some(fs.xmm[8][0]); + known_registers[X64Register::XMM(XMM::XMM9).to_index().0] = Some(fs.xmm[9][0]); + known_registers[X64Register::XMM(XMM::XMM10).to_index().0] = Some(fs.xmm[10][0]); + known_registers[X64Register::XMM(XMM::XMM11).to_index().0] = Some(fs.xmm[11][0]); + known_registers[X64Register::XMM(XMM::XMM12).to_index().0] = Some(fs.xmm[12][0]); + known_registers[X64Register::XMM(XMM::XMM13).to_index().0] = Some(fs.xmm[13][0]); + known_registers[X64Register::XMM(XMM::XMM14).to_index().0] = Some(fs.xmm[14][0]); + known_registers[X64Register::XMM(XMM::XMM15).to_index().0] = Some(fs.xmm[15][0]); FaultInfo { faulting_addr: si_addr, diff --git a/lib/runtime-core/src/loader.rs b/lib/runtime-core/src/loader.rs index 4f843a54d..f50d3a7a0 100644 --- a/lib/runtime-core/src/loader.rs +++ b/lib/runtime-core/src/loader.rs @@ -22,11 +22,11 @@ pub trait Instance { type Error: Debug; fn call(&mut self, id: usize, args: &[Value]) -> Result; fn read_memory(&mut self, _offset: u32, _len: u32) -> Result, Self::Error> { - unimplemented!() + unimplemented!("Instance::read_memory") } fn write_memory(&mut self, _offset: u32, _len: u32, _buf: &[u8]) -> Result<(), Self::Error> { - unimplemented!() + unimplemented!("Instance::write_memory") } } @@ -122,15 +122,15 @@ unsafe impl Sync for CodeMemory {} #[cfg(not(unix))] impl CodeMemory { pub fn new(_size: usize) -> CodeMemory { - unimplemented!(); + unimplemented!("CodeMemory::new"); } pub fn make_executable(&self) { - unimplemented!(); + unimplemented!("CodeMemory::make_executable"); } pub fn make_writable(&self) { - unimplemented!(); + unimplemented!("CodeMemory::make_writable"); } } diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 6cc02343f..1bf914a46 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -29,7 +29,7 @@ pub struct ModuleInner { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ModuleInfo { - // This are strictly local and the typsystem ensures that. + // This are strictly local and the typesystem ensures that. pub memories: Map, pub globals: Map, pub tables: Map, diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 7b8dcd2b1..6025abe60 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -672,6 +672,37 @@ pub mod x64 { stack_offset -= 1; stack[stack_offset] = stack.as_ptr().offset(last_stack_offset as isize) as usize as u64; // rbp + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM15).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM14).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM13).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM12).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM11).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM10).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM9).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM8).to_index().0].unwrap_or(0); stack_offset -= 1; stack[stack_offset] = known_registers[X64Register::XMM(XMM::XMM7).to_index().0].unwrap_or(0); @@ -780,10 +811,10 @@ pub mod x64 { pub unsafe fn read_stack<'a, I: Iterator, F: Fn() -> I + 'a>( versions: F, mut stack: *const u64, - initially_known_registers: [Option; 24], + initially_known_registers: [Option; 32], mut initial_address: Option, ) -> ExecutionStateImage { - let mut known_registers: [Option; 24] = initially_known_registers; + let mut known_registers: [Option; 32] = initially_known_registers; let mut results: Vec = vec![]; let mut was_baseline = true; @@ -1023,6 +1054,14 @@ pub mod x64 { XMM5, XMM6, XMM7, + XMM8, + XMM9, + XMM10, + XMM11, + XMM12, + XMM13, + XMM14, + XMM15, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -1066,6 +1105,14 @@ pub mod x64 { 22 => X64Register::XMM(XMM::XMM5), 23 => X64Register::XMM(XMM::XMM6), 24 => X64Register::XMM(XMM::XMM7), + 25 => X64Register::XMM(XMM::XMM8), + 26 => X64Register::XMM(XMM::XMM9), + 27 => X64Register::XMM(XMM::XMM10), + 28 => X64Register::XMM(XMM::XMM11), + 29 => X64Register::XMM(XMM::XMM12), + 30 => X64Register::XMM(XMM::XMM13), + 31 => X64Register::XMM(XMM::XMM14), + 32 => X64Register::XMM(XMM::XMM15), _ => return None, }) } diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 0014e13cd..2a38beb1e 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -3,7 +3,7 @@ use crate::{ export::{Context, Export, FuncPointer}, import::IsExport, types::{FuncSig, NativeWasmType, Type, WasmExternType}, - vm::{self, Ctx}, + vm, }; use std::{ any::Any, @@ -52,16 +52,21 @@ impl fmt::Display for WasmTrapInfo { /// of the `Func` struct. pub trait Kind {} -pub type Trampoline = unsafe extern "C" fn(*mut Ctx, NonNull, *const u64, *mut u64); +pub type Trampoline = unsafe extern "C" fn( + vmctx: *mut vm::Ctx, + func: NonNull, + args: *const u64, + rets: *mut u64, +); pub type Invoke = unsafe extern "C" fn( - Trampoline, - *mut Ctx, - NonNull, - *const u64, - *mut u64, - *mut WasmTrapInfo, - *mut Option>, - Option>, + trampoline: Trampoline, + vmctx: *mut vm::Ctx, + func: NonNull, + args: *const u64, + rets: *mut u64, + trap_info: *mut WasmTrapInfo, + user_error: *mut Option>, + extra: Option>, ) -> bool; /// TODO(lachlan): Naming TBD. @@ -91,29 +96,82 @@ impl Wasm { /// This type, as part of the `Func` type signature, represents a function that is created /// by the host. pub struct Host(()); + impl Kind for Wasm {} impl Kind for Host {} +/// Represents a list of WebAssembly values. pub trait WasmTypeList { type CStruct; + type RetArray: AsMut<[u64]>; + + /// Construct `Self` based on an array of returned values. fn from_ret_array(array: Self::RetArray) -> Self; + + /// Generates an empty array that will hold the returned values of + /// the WebAssembly function. fn empty_ret_array() -> Self::RetArray; + + /// Transforms C values into Rust values. fn from_c_struct(c_struct: Self::CStruct) -> Self; + + /// Transforms Rust values into C values. fn into_c_struct(self) -> Self::CStruct; + + /// Get types of the current values. fn types() -> &'static [Type]; + + /// This method is used to distribute the values onto a function, + /// e.g. `(1, 2).call(func, …)`. This form is unlikely to be used + /// directly in the code, see the `Func:call` implementation. unsafe fn call( self, f: NonNull, wasm: Wasm, - ctx: *mut Ctx, + ctx: *mut vm::Ctx, ) -> Result where Rets: WasmTypeList; } -pub trait ExternalFunction +/// Empty trait to specify the kind of `ExternalFunction`: With or +/// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the +/// `ImplicitVmCtx` structures. +/// +/// This type is never aimed to be used by a user. It is used by the +/// trait system to automatically generate an appropriate `wrap` +/// function. +pub trait ExternalFunctionKind {} + +/// This empty structure indicates that an external function must +/// contain an explicit `vm::Ctx` argument (at first position). +/// +/// ```rs,ignore +/// fn add_one(_: mut &vm::Ctx, x: i32) -> i32 { +/// x + 1 +/// } +/// ``` +pub struct ExplicitVmCtx {} + +/// This empty structure indicates that an external function has no +/// `vm::Ctx` argument (at first position). Its signature is: +/// +/// ```rs,ignore +/// fn add_one(x: i32) -> i32 { +/// x + 1 +/// } +/// ``` +pub struct ImplicitVmCtx {} + +impl ExternalFunctionKind for ExplicitVmCtx {} +impl ExternalFunctionKind for ImplicitVmCtx {} + +/// Represents a function that can be converted to a `vm::Func` +/// (function pointer) that can be called within WebAssembly. +pub trait ExternalFunction where + Kind: ExternalFunctionKind, Args: WasmTypeList, Rets: WasmTypeList, { @@ -149,19 +207,11 @@ where } } -// pub fn Func<'a, Args, Rets, F>(f: F) -> Func<'a, Args, Rets, Unsafe> -// where -// Args: WasmTypeList, -// Rets: WasmTypeList, -// F: ExternalFunction -// { -// Func::new(f) -// } - +/// Represents a function that can be used by WebAssembly. pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> { inner: Inner, f: NonNull, - ctx: *mut Ctx, + ctx: *mut vm::Ctx, _phantom: PhantomData<(&'a (), Args, Rets)>, } @@ -176,7 +226,7 @@ where pub(crate) unsafe fn from_raw_parts( inner: Wasm, f: NonNull, - ctx: *mut Ctx, + ctx: *mut vm::Ctx, ) -> Func<'a, Args, Rets, Wasm> { Func { inner, @@ -196,9 +246,10 @@ where Args: WasmTypeList, Rets: WasmTypeList, { - pub fn new(f: F) -> Func<'a, Args, Rets, Host> + pub fn new(f: F) -> Func<'a, Args, Rets, Host> where - F: ExternalFunction, + Kind: ExternalFunctionKind, + F: ExternalFunction, { Func { inner: Host(()), @@ -215,9 +266,12 @@ where Rets: WasmTypeList, Inner: Kind, { + /// Returns the types of the function inputs. pub fn params(&self) -> &'static [Type] { Args::types() } + + /// Returns the types of the function outputs. pub fn returns(&self) -> &'static [Type] { Rets::types() } @@ -226,62 +280,83 @@ where impl WasmTypeList for Infallible { type CStruct = Infallible; type RetArray = [u64; 0]; + fn from_ret_array(_: Self::RetArray) -> Self { unreachable!() } + fn empty_ret_array() -> Self::RetArray { unreachable!() } + fn from_c_struct(_: Self::CStruct) -> Self { unreachable!() } + fn into_c_struct(self) -> Self::CStruct { unreachable!() } + fn types() -> &'static [Type] { &[] } + #[allow(non_snake_case)] - unsafe fn call( + unsafe fn call( self, _: NonNull, _: Wasm, - _: *mut Ctx, - ) -> Result { + _: *mut vm::Ctx, + ) -> Result + where + Rets: WasmTypeList, + { unreachable!() } } -impl WasmTypeList for (A,) { +impl WasmTypeList for (A,) +where + A: WasmExternType, +{ type CStruct = S1; type RetArray = [u64; 1]; + fn from_ret_array(array: Self::RetArray) -> Self { (WasmExternType::from_native(NativeWasmType::from_binary( array[0], )),) } + fn empty_ret_array() -> Self::RetArray { [0u64] } + fn from_c_struct(c_struct: Self::CStruct) -> Self { let S1(a) = c_struct; (WasmExternType::from_native(a),) } + fn into_c_struct(self) -> Self::CStruct { #[allow(unused_parens, non_snake_case)] let (a,) = self; S1(WasmExternType::to_native(a)) } + fn types() -> &'static [Type] { &[A::Native::TYPE] } + #[allow(non_snake_case)] - unsafe fn call( + unsafe fn call( self, f: NonNull, wasm: Wasm, - ctx: *mut Ctx, - ) -> Result { + ctx: *mut vm::Ctx, + ) -> Result + where + Rets: WasmTypeList, + { let (a,) = self; let args = [a.to_native().to_binary()]; let mut rets = Rets::empty_ret_array(); @@ -323,34 +398,57 @@ where macro_rules! impl_traits { ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { #[repr($repr)] - pub struct $struct_name <$( $x: WasmExternType ),*> ( $( <$x as WasmExternType>::Native ),* ); + pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* ) + where + $( $x: WasmExternType ),*; - impl< $( $x: WasmExternType, )* > WasmTypeList for ( $( $x ),* ) { + impl< $( $x ),* > WasmTypeList for ( $( $x ),* ) + where + $( $x: WasmExternType ),* + { type CStruct = $struct_name<$( $x ),*>; + type RetArray = [u64; count_idents!( $( $x ),* )]; + fn from_ret_array(array: Self::RetArray) -> Self { #[allow(non_snake_case)] let [ $( $x ),* ] = array; + ( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* ) } + fn empty_ret_array() -> Self::RetArray { [0; count_idents!( $( $x ),* )] } + fn from_c_struct(c_struct: Self::CStruct) -> Self { #[allow(non_snake_case)] let $struct_name ( $( $x ),* ) = c_struct; + ( $( WasmExternType::from_native($x) ),* ) } + fn into_c_struct(self) -> Self::CStruct { #[allow(unused_parens, non_snake_case)] let ( $( $x ),* ) = self; + $struct_name ( $( WasmExternType::to_native($x) ),* ) } + fn types() -> &'static [Type] { - &[$( $x::Native::TYPE, )*] + &[$( $x::Native::TYPE ),*] } + #[allow(non_snake_case)] - unsafe fn call(self, f: NonNull, wasm: Wasm, ctx: *mut Ctx) -> Result { + unsafe fn call( + self, + f: NonNull, + wasm: Wasm, + ctx: *mut vm::Ctx, + ) -> Result + where + Rets: WasmTypeList + { #[allow(unused_parens)] let ( $( $x ),* ) = self; let args = [ $( $x.to_native().to_binary()),* ]; @@ -358,7 +456,16 @@ macro_rules! impl_traits { let mut trap = WasmTrapInfo::Unknown; let mut user_error = None; - if (wasm.invoke)(wasm.trampoline, ctx, f, args.as_ptr(), rets.as_mut().as_mut_ptr(), &mut trap, &mut user_error, wasm.invoke_env) { + if (wasm.invoke)( + wasm.trampoline, + ctx, + f, + args.as_ptr(), + rets.as_mut().as_mut_ptr(), + &mut trap, + &mut user_error, + wasm.invoke_env + ) { Ok(Rets::from_ret_array(rets)) } else { if let Some(data) = user_error { @@ -370,18 +477,36 @@ macro_rules! impl_traits { } } - impl< $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap> ExternalFunction<($( $x ),*), Rets> for FN { + impl< $( $x, )* Rets, Trap, FN > ExternalFunction for FN + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap, + { #[allow(non_snake_case)] fn to_raw(&self) -> NonNull { if mem::size_of::() == 0 { /// This is required for the llvm backend to be able to unwind through this function. #[cfg_attr(nightly, unwind(allowed))] - extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct { + extern fn wrap<$( $x, )* Rets, Trap, FN>( + vmctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )* + ) -> Rets::CStruct + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap, + { let f: FN = unsafe { mem::transmute_copy(&()) }; - let err = match panic::catch_unwind(panic::AssertUnwindSafe(|| { - f( ctx $( ,WasmExternType::from_native($x) )* ).report() - })) { + let err = match panic::catch_unwind( + panic::AssertUnwindSafe( + || { + f(vmctx $( , WasmExternType::from_native($x) )* ).report() + } + ) + ) { Ok(Ok(returns)) => return returns.into_c_struct(), Ok(Err(err)) => { let b: Box<_> = err.into(); @@ -391,28 +516,99 @@ macro_rules! impl_traits { }; unsafe { - (&*ctx.module).runnable_module.do_early_trap(err) + (&*vmctx.module).runnable_module.do_early_trap(err) } } NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap() } else { - assert_eq!(mem::size_of::(), mem::size_of::(), "you cannot use a closure that captures state for `Func`."); + assert_eq!( + mem::size_of::(), + mem::size_of::(), + "you cannot use a closure that captures state for `Func`." + ); + NonNull::new(unsafe { - ::std::mem::transmute_copy::<_, *mut vm::Func>(self) + mem::transmute_copy::<_, *mut vm::Func>(self) }).unwrap() } } } - impl<'a, $( $x: WasmExternType, )* Rets> Func<'a, ( $( $x ),* ), Rets, Wasm> + impl< $( $x, )* Rets, Trap, FN > ExternalFunction for FN where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn($( $x, )*) -> Trap, + { + #[allow(non_snake_case)] + fn to_raw(&self) -> NonNull { + if mem::size_of::() == 0 { + /// This is required for the llvm backend to be able to unwind through this function. + #[cfg_attr(nightly, unwind(allowed))] + extern fn wrap<$( $x, )* Rets, Trap, FN>( + vmctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )* + ) -> Rets::CStruct + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn($( $x, )*) -> Trap, + { + let f: FN = unsafe { mem::transmute_copy(&()) }; + + let err = match panic::catch_unwind( + panic::AssertUnwindSafe( + || { + f($( WasmExternType::from_native($x), )* ).report() + } + ) + ) { + Ok(Ok(returns)) => return returns.into_c_struct(), + Ok(Err(err)) => { + let b: Box<_> = err.into(); + b as Box + }, + Err(err) => err, + }; + + unsafe { + (&*vmctx.module).runnable_module.do_early_trap(err) + } + } + + NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap() + } else { + assert_eq!( + mem::size_of::(), + mem::size_of::(), + "you cannot use a closure that captures state for `Func`." + ); + + NonNull::new(unsafe { + mem::transmute_copy::<_, *mut vm::Func>(self) + }).unwrap() + } + } + } + + impl<'a $( , $x )*, Rets> Func<'a, ( $( $x ),* ), Rets, Wasm> + where + $( $x: WasmExternType, )* Rets: WasmTypeList, { #[allow(non_snake_case)] pub fn call(&self, $( $x: $x, )* ) -> Result { #[allow(unused_parens)] - unsafe { <( $( $x ),* ) as WasmTypeList>::call(( $($x),* ), self.f, self.inner, self.ctx) } + unsafe { + <( $( $x ),* ) as WasmTypeList>::call( + ( $( $x ),* ), + self.f, + self.inner, + self.ctx + ) + } } } }; @@ -463,9 +659,57 @@ where #[cfg(test)] mod tests { use super::*; + + macro_rules! test_func_arity_n { + ($test_name:ident, $($x:ident),*) => { + #[test] + fn $test_name() { + use crate::vm; + + fn with_vmctx(_: &mut vm::Ctx, $($x: i32),*) -> i32 { + vec![$($x),*].iter().sum() + } + + fn without_vmctx($($x: i32),*) -> i32 { + vec![$($x),*].iter().sum() + } + + let _func = Func::new(with_vmctx); + let _func = Func::new(without_vmctx); + } + } + } + + #[test] + fn test_func_arity_0() { + fn foo(_: &mut vm::Ctx) -> i32 { + 0 + } + + fn bar() -> i32 { + 0 + } + + let _ = Func::new(foo); + let _ = Func::new(bar); + } + + test_func_arity_n!(test_func_arity_1, a); + test_func_arity_n!(test_func_arity_2, a, b); + test_func_arity_n!(test_func_arity_3, a, b, c); + test_func_arity_n!(test_func_arity_4, a, b, c, d); + test_func_arity_n!(test_func_arity_5, a, b, c, d, e); + test_func_arity_n!(test_func_arity_6, a, b, c, d, e, f); + test_func_arity_n!(test_func_arity_7, a, b, c, d, e, f, g); + test_func_arity_n!(test_func_arity_8, a, b, c, d, e, f, g, h); + test_func_arity_n!(test_func_arity_9, a, b, c, d, e, f, g, h, i); + test_func_arity_n!(test_func_arity_10, a, b, c, d, e, f, g, h, i, j); + test_func_arity_n!(test_func_arity_11, a, b, c, d, e, f, g, h, i, j, k); + test_func_arity_n!(test_func_arity_12, a, b, c, d, e, f, g, h, i, j, k, l); + #[test] fn test_call() { - fn foo(_ctx: &mut Ctx, a: i32, b: i32) -> (i32, i32) { + fn foo(_ctx: &mut vm::Ctx, a: i32, b: i32) -> (i32, i32) { (a, b) } @@ -476,7 +720,7 @@ mod tests { fn test_imports() { use crate::{func, imports}; - fn foo(_ctx: &mut Ctx, a: i32) -> i32 { + fn foo(_ctx: &mut vm::Ctx, a: i32) -> i32 { a } diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index fd8cebbec..2bb734a04 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -916,15 +916,15 @@ mod vm_ctx_tests { } fn get_trampoline(&self, _module: &ModuleInfo, _sig_index: SigIndex) -> Option { - unimplemented!() + unimplemented!("generate_module::get_trampoline") } unsafe fn do_early_trap(&self, _: Box) -> ! { - unimplemented!() + unimplemented!("generate_module::do_early_trap") } } impl CacheGen for Placeholder { fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> { - unimplemented!() + unimplemented!("generate_module::generate_cache") } } diff --git a/lib/runtime-core/src/vmcalls.rs b/lib/runtime-core/src/vmcalls.rs index 5205a0d69..32aa9367f 100644 --- a/lib/runtime-core/src/vmcalls.rs +++ b/lib/runtime-core/src/vmcalls.rs @@ -10,7 +10,7 @@ use crate::{ // +*****************************+ // | LOCAL MEMORIES | -// +****************************+ +// +*****************************+ pub unsafe extern "C" fn local_static_memory_grow( ctx: &mut vm::Ctx, @@ -72,7 +72,7 @@ pub unsafe extern "C" fn local_dynamic_memory_size( // +*****************************+ // | IMPORTED MEMORIES | -// +****************************+ +// +*****************************+ pub unsafe extern "C" fn imported_static_memory_grow( ctx: &mut vm::Ctx, @@ -140,7 +140,7 @@ pub unsafe extern "C" fn imported_dynamic_memory_size( // +*****************************+ // | LOCAL TABLES | -// +****************************+ +// +*****************************+ pub unsafe extern "C" fn local_table_grow( ctx: &mut vm::Ctx, @@ -150,11 +150,11 @@ pub unsafe extern "C" fn local_table_grow( let _ = table_index; let _ = delta; let _ = ctx; - unimplemented!() + unimplemented!("vmcalls::local_table_grow") } pub unsafe extern "C" fn local_table_size(ctx: &vm::Ctx, table_index: LocalTableIndex) -> u32 { let _ = table_index; let _ = ctx; - unimplemented!() + unimplemented!("vmcalls::local_table_size") } diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 2e42055c2..d2bcb83a7 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,17 +9,17 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } lazy_static = "1.4" memmap = "0.7" [dependencies.wasmer-runtime-core] path = "../runtime-core" -version = "0.8.0" +version = "0.9.0" [dependencies.wasmer-clif-backend] path = "../clif-backend" -version = "0.8.0" +version = "0.9.0" optional = true [dev-dependencies] diff --git a/lib/runtime/README.md b/lib/runtime/README.md index 769e4cdb6..ce18500bf 100644 --- a/lib/runtime/README.md +++ b/lib/runtime/README.md @@ -94,8 +94,8 @@ fn main() -> error::Result<()> { ## Additional Notes -The `wasmer-runtime` crate is build to support multiple compiler -backends. We support have a [Cranelift] backend in the +The `wasmer-runtime` crate is built to support multiple compiler +backends. We support having a [Cranelift] backend in the [`wasmer-clif-backend`] crate, a [LLVM] backend in the [`wasmer-llvm-backend`] crate, and the [Singlepass] backend in the [`wasmer-singlepass-backend`] crate. Currently, the Cranelift backend diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 2945ff3d5..aedd938ae 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -92,6 +92,7 @@ pub use wasmer_runtime_core::export::Export; pub use wasmer_runtime_core::global::Global; pub use wasmer_runtime_core::import::ImportObject; pub use wasmer_runtime_core::instance::{DynFunc, Instance}; +pub use wasmer_runtime_core::memory::ptr::{Array, Item, WasmPtr}; pub use wasmer_runtime_core::memory::Memory; pub use wasmer_runtime_core::module::Module; pub use wasmer_runtime_core::table::Table; diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 5243cc601..7abd4a158 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-singlepass-backend" -version = "0.8.0" +version = "0.9.0" repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime single pass compiler backend" license = "MIT" @@ -9,8 +9,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmparser = "0.39.1" +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } dynasm = "0.3.2" dynasmrt = "0.3.1" lazy_static = "1.4" diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7e3a9ed5f..f4411a74c 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1,16 +1,18 @@ #![allow(clippy::forget_copy)] // Used by dynasm. #![warn(unused_imports)] -use crate::emitter_x64::*; -use crate::machine::*; -use crate::protect_unix; +use crate::{emitter_x64::*, machine::*, protect_unix}; use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; use smallvec::SmallVec; -use std::ptr::NonNull; use std::{ any::Any, collections::{BTreeMap, HashMap}, + ffi::c_void, + iter, mem, + ptr::NonNull, + slice, sync::{Arc, RwLock}, + usize, }; use wasmer_runtime_core::{ backend::{ @@ -27,14 +29,14 @@ use wasmer_runtime_core::{ ModuleStateMap, OffsetInfo, SuspendOffset, WasmAbstractValue, }, structures::{Map, TypedIndex}, - typed_func::Wasm, + typed_func::{Trampoline, Wasm, WasmTrapInfo}, types::{ FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, }, vm::{self, LocalGlobal, LocalTable, INTERNALS_SIZE}, + wasmparser::{MemoryImmediate, Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}, }; -use wasmparser::{MemoryImmediate, Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}; lazy_static! { /// Performs a System V call to `target` with [stack_top..stack_base] as the argument list, from right to left. @@ -118,8 +120,8 @@ lazy_static! { ; ret ); let buf = assembler.finalize().unwrap(); - let ret = unsafe { ::std::mem::transmute(buf.ptr(offset)) }; - ::std::mem::forget(buf); + let ret = unsafe { mem::transmute(buf.ptr(offset)) }; + mem::forget(buf); ret }; } @@ -227,7 +229,7 @@ impl RunnableModule for X64ExecutionContext { 14: 41 ff e3 jmpq *%r11 */ #[repr(packed)] - struct Trampoline { + struct LocalTrampoline { movabsq_rax: [u8; 2], addr_rax: u64, movabsq_r11: [u8; 2], @@ -238,7 +240,7 @@ impl RunnableModule for X64ExecutionContext { self.code.make_writable(); let trampoline = &mut *(self.function_pointers[self.func_import_count + idx].0 - as *const Trampoline as *mut Trampoline); + as *const LocalTrampoline as *mut LocalTrampoline); trampoline.movabsq_rax[0] = 0x48; trampoline.movabsq_rax[1] = 0xb8; trampoline.addr_rax = target_address as u64; @@ -255,16 +257,8 @@ impl RunnableModule for X64ExecutionContext { } fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { - use std::ffi::c_void; - use wasmer_runtime_core::typed_func::WasmTrapInfo; - unsafe extern "C" fn invoke( - _trampoline: unsafe extern "C" fn( - *mut vm::Ctx, - NonNull, - *const u64, - *mut u64, - ), + _trampoline: Trampoline, ctx: *mut vm::Ctx, func: NonNull, args: *const u64, @@ -275,12 +269,10 @@ impl RunnableModule for X64ExecutionContext { ) -> bool { let rm: &Box = &(&*(*ctx).module).runnable_module; let execution_context = - ::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm); + mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm); - let args = std::slice::from_raw_parts( - args, - num_params_plus_one.unwrap().as_ptr() as usize - 1, - ); + let args = + slice::from_raw_parts(args, num_params_plus_one.unwrap().as_ptr() as usize - 1); let args_reverse: SmallVec<[u64; 8]> = args.iter().cloned().rev().collect(); let ret = match protect_unix::call_protected( || { @@ -1737,7 +1729,7 @@ impl X64FunctionCode { control_stack: &mut [ControlFrame], ) -> usize { if !m.track_state { - return ::std::usize::MAX; + return usize::MAX; } let last_frame = control_stack.last_mut().unwrap(); let mut diff = m.state.diff(&last_frame.state); @@ -1853,7 +1845,7 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::GPR(GPR::RAX), ); - assert_eq!(self.machine.state.wasm_inst_offset, ::std::usize::MAX); + assert_eq!(self.machine.state.wasm_inst_offset, usize::MAX); Ok(()) } @@ -2341,18 +2333,109 @@ impl FunctionCodeGenerator for X64FunctionCode { Condition::Equal, Location::Imm32(0), ), - Operator::I32Clz => Self::emit_xcnt_i32( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_lzcnt, - ), - Operator::I32Ctz => Self::emit_xcnt_i32( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_tzcnt, - ), + Operator::I32Clz => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src = match loc { + Location::Imm32(_) | Location::Memory(_, _) => { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmp)); + tmp + } + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let ret = self.machine.acquire_locations( + a, + &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let dst = match ret { + Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let zero_path = a.get_label(); + let end = a.get_label(); + + a.emit_test_gpr_64(src); + a.emit_jmp(Condition::Equal, zero_path); + a.emit_bsr(Size::S32, Location::GPR(src), Location::GPR(dst)); + a.emit_xor(Size::S32, Location::Imm32(31), Location::GPR(dst)); + a.emit_jmp(Condition::None, end); + a.emit_label(zero_path); + a.emit_mov(Size::S32, Location::Imm32(32), Location::GPR(dst)); + a.emit_label(end); + + match loc { + Location::Imm32(_) | Location::Memory(_, _) => { + self.machine.release_temp_gpr(src); + } + _ => {} + }; + match ret { + Location::Memory(_, _) => { + a.emit_mov(Size::S32, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); + } + _ => {} + }; + } + Operator::I32Ctz => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src = match loc { + Location::Imm32(_) | Location::Memory(_, _) => { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmp)); + tmp + } + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let ret = self.machine.acquire_locations( + a, + &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let dst = match ret { + Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let zero_path = a.get_label(); + let end = a.get_label(); + + a.emit_test_gpr_64(src); + a.emit_jmp(Condition::Equal, zero_path); + a.emit_bsf(Size::S32, Location::GPR(src), Location::GPR(dst)); + a.emit_jmp(Condition::None, end); + a.emit_label(zero_path); + a.emit_mov(Size::S32, Location::Imm32(32), Location::GPR(dst)); + a.emit_label(end); + + match loc { + Location::Imm32(_) | Location::Memory(_, _) => { + self.machine.release_temp_gpr(src); + } + _ => {} + }; + match ret { + Location::Memory(_, _) => { + a.emit_mov(Size::S32, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); + } + _ => {} + }; + } Operator::I32Popcnt => Self::emit_xcnt_i32( a, &mut self.machine, @@ -2632,18 +2715,109 @@ impl FunctionCodeGenerator for X64FunctionCode { Condition::Equal, Location::Imm64(0), ), - Operator::I64Clz => Self::emit_xcnt_i64( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_lzcnt, - ), - Operator::I64Ctz => Self::emit_xcnt_i64( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_tzcnt, - ), + Operator::I64Clz => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src = match loc { + Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S64, loc, Location::GPR(tmp)); + tmp + } + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let ret = self.machine.acquire_locations( + a, + &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let dst = match ret { + Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let zero_path = a.get_label(); + let end = a.get_label(); + + a.emit_test_gpr_64(src); + a.emit_jmp(Condition::Equal, zero_path); + a.emit_bsr(Size::S64, Location::GPR(src), Location::GPR(dst)); + a.emit_xor(Size::S64, Location::Imm32(63), Location::GPR(dst)); + a.emit_jmp(Condition::None, end); + a.emit_label(zero_path); + a.emit_mov(Size::S64, Location::Imm32(64), Location::GPR(dst)); + a.emit_label(end); + + match loc { + Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { + self.machine.release_temp_gpr(src); + } + _ => {} + }; + match ret { + Location::Memory(_, _) => { + a.emit_mov(Size::S64, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); + } + _ => {} + }; + } + Operator::I64Ctz => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src = match loc { + Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S64, loc, Location::GPR(tmp)); + tmp + } + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let ret = self.machine.acquire_locations( + a, + &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let dst = match ret { + Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let zero_path = a.get_label(); + let end = a.get_label(); + + a.emit_test_gpr_64(src); + a.emit_jmp(Condition::Equal, zero_path); + a.emit_bsf(Size::S64, Location::GPR(src), Location::GPR(dst)); + a.emit_jmp(Condition::None, end); + a.emit_label(zero_path); + a.emit_mov(Size::S64, Location::Imm32(64), Location::GPR(dst)); + a.emit_label(end); + + match loc { + Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { + self.machine.release_temp_gpr(src); + } + _ => {} + }; + match ret { + Location::Memory(_, _) => { + a.emit_mov(Size::S64, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); + } + _ => {} + }; + } Operator::I64Popcnt => Self::emit_xcnt_i64( a, &mut self.machine, @@ -2812,18 +2986,211 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.value_stack, Assembler::emit_vdivss, ), - Operator::F32Max => Self::emit_fp_binop_avx( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_vmaxss, - ), - Operator::F32Min => Self::emit_fp_binop_avx( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_vminss, - ), + Operator::F32Max => { + let src2 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src1 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmp1 = self.machine.acquire_temp_xmm().unwrap(); + let tmp2 = self.machine.acquire_temp_xmm().unwrap(); + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + let tmpg2 = self.machine.acquire_temp_gpr().unwrap(); + + let src1 = match src1 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src1, Location::XMM(tmp1)); + tmp1 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + _ => unreachable!(), + }; + let src2 = match src2 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src2, Location::XMM(tmp2)); + tmp2 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + _ => unreachable!(), + }; + + let tmp_xmm1 = XMM::XMM8; + let tmp_xmm2 = XMM::XMM9; + let tmp_xmm3 = XMM::XMM10; + + static CANONICAL_NAN: u128 = 0x7FC0_0000; + a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::XMM(src2), Location::GPR(tmpg2)); + a.emit_cmp(Size::S32, Location::GPR(tmpg2), Location::GPR(tmpg1)); + a.emit_vmaxss(src1, XMMOrMemory::XMM(src2), tmp_xmm1); + let label1 = a.get_label(); + let label2 = a.get_label(); + a.emit_jmp(Condition::NotEqual, label1); + a.emit_vmovaps(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); + a.emit_jmp(Condition::None, label2); + a.emit_label(label1); + a.emit_vxorps(tmp_xmm2, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm2); + a.emit_label(label2); + a.emit_vcmpeqss(src1, XMMOrMemory::XMM(src2), tmp_xmm3); + a.emit_vblendvps(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); + a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src2), src1); + // load float canonical nan + a.emit_mov( + Size::S64, + Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); + match ret { + Location::XMM(x) => { + a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(x)); + } + Location::Memory(_, _) | Location::GPR(_) => { + a.emit_mov(Size::S64, Location::XMM(src1), ret); + } + _ => unreachable!(), + } + + self.machine.release_temp_gpr(tmpg2); + self.machine.release_temp_gpr(tmpg1); + self.machine.release_temp_xmm(tmp2); + self.machine.release_temp_xmm(tmp1); + } + Operator::F32Min => { + let src2 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src1 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmp1 = self.machine.acquire_temp_xmm().unwrap(); + let tmp2 = self.machine.acquire_temp_xmm().unwrap(); + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + let tmpg2 = self.machine.acquire_temp_gpr().unwrap(); + + let src1 = match src1 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src1, Location::XMM(tmp1)); + tmp1 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + _ => unreachable!(), + }; + let src2 = match src2 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src2, Location::XMM(tmp2)); + tmp2 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + _ => unreachable!(), + }; + + let tmp_xmm1 = XMM::XMM8; + let tmp_xmm2 = XMM::XMM9; + let tmp_xmm3 = XMM::XMM10; + + static NEG_ZERO: u128 = 0x8000_0000; + static CANONICAL_NAN: u128 = 0x7FC0_0000; + a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::XMM(src2), Location::GPR(tmpg2)); + a.emit_cmp(Size::S32, Location::GPR(tmpg2), Location::GPR(tmpg1)); + a.emit_vminss(src1, XMMOrMemory::XMM(src2), tmp_xmm1); + let label1 = a.get_label(); + let label2 = a.get_label(); + a.emit_jmp(Condition::NotEqual, label1); + a.emit_vmovaps(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); + a.emit_jmp(Condition::None, label2); + a.emit_label(label1); + // load float -0.0 + a.emit_mov( + Size::S64, + Location::Imm64((&NEG_ZERO as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov( + Size::S64, + Location::Memory(tmpg1, 0), + Location::XMM(tmp_xmm2), + ); + a.emit_label(label2); + a.emit_vcmpeqss(src1, XMMOrMemory::XMM(src2), tmp_xmm3); + a.emit_vblendvps(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); + a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src2), src1); + // load float canonical nan + a.emit_mov( + Size::S64, + Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); + match ret { + Location::XMM(x) => { + a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(x)); + } + Location::Memory(_, _) | Location::GPR(_) => { + a.emit_mov(Size::S64, Location::XMM(src1), ret); + } + _ => unreachable!(), + } + + self.machine.release_temp_gpr(tmpg2); + self.machine.release_temp_gpr(tmpg1); + self.machine.release_temp_xmm(tmp2); + self.machine.release_temp_xmm(tmp1); + } Operator::F32Eq => Self::emit_fp_cmpop_avx( a, &mut self.machine, @@ -2990,18 +3357,211 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.value_stack, Assembler::emit_vdivsd, ), - Operator::F64Max => Self::emit_fp_binop_avx( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_vmaxsd, - ), - Operator::F64Min => Self::emit_fp_binop_avx( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_vminsd, - ), + Operator::F64Max => { + let src2 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src1 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmp1 = self.machine.acquire_temp_xmm().unwrap(); + let tmp2 = self.machine.acquire_temp_xmm().unwrap(); + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + let tmpg2 = self.machine.acquire_temp_gpr().unwrap(); + + let src1 = match src1 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src1, Location::XMM(tmp1)); + tmp1 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + _ => unreachable!(), + }; + let src2 = match src2 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src2, Location::XMM(tmp2)); + tmp2 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + _ => unreachable!(), + }; + + let tmp_xmm1 = XMM::XMM8; + let tmp_xmm2 = XMM::XMM9; + let tmp_xmm3 = XMM::XMM10; + + static CANONICAL_NAN: u128 = 0x7FF8_0000_0000_0000; + a.emit_mov(Size::S64, Location::XMM(src1), Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::XMM(src2), Location::GPR(tmpg2)); + a.emit_cmp(Size::S64, Location::GPR(tmpg2), Location::GPR(tmpg1)); + a.emit_vmaxsd(src1, XMMOrMemory::XMM(src2), tmp_xmm1); + let label1 = a.get_label(); + let label2 = a.get_label(); + a.emit_jmp(Condition::NotEqual, label1); + a.emit_vmovapd(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); + a.emit_jmp(Condition::None, label2); + a.emit_label(label1); + a.emit_vxorpd(tmp_xmm2, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm2); + a.emit_label(label2); + a.emit_vcmpeqsd(src1, XMMOrMemory::XMM(src2), tmp_xmm3); + a.emit_vblendvpd(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); + a.emit_vcmpunordsd(src1, XMMOrMemory::XMM(src2), src1); + // load float canonical nan + a.emit_mov( + Size::S64, + Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_vblendvpd(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); + match ret { + Location::XMM(x) => { + a.emit_vmovapd(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(x)); + } + Location::Memory(_, _) | Location::GPR(_) => { + a.emit_mov(Size::S64, Location::XMM(src1), ret); + } + _ => unreachable!(), + } + + self.machine.release_temp_gpr(tmpg2); + self.machine.release_temp_gpr(tmpg1); + self.machine.release_temp_xmm(tmp2); + self.machine.release_temp_xmm(tmp1); + } + Operator::F64Min => { + let src2 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src1 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmp1 = self.machine.acquire_temp_xmm().unwrap(); + let tmp2 = self.machine.acquire_temp_xmm().unwrap(); + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + let tmpg2 = self.machine.acquire_temp_gpr().unwrap(); + + let src1 = match src1 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src1, Location::XMM(tmp1)); + tmp1 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + _ => unreachable!(), + }; + let src2 = match src2 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src2, Location::XMM(tmp2)); + tmp2 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + _ => unreachable!(), + }; + + let tmp_xmm1 = XMM::XMM8; + let tmp_xmm2 = XMM::XMM9; + let tmp_xmm3 = XMM::XMM10; + + static NEG_ZERO: u128 = 0x8000_0000_0000_0000; + static CANONICAL_NAN: u128 = 0x7FF8_0000_0000_0000; + a.emit_mov(Size::S64, Location::XMM(src1), Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::XMM(src2), Location::GPR(tmpg2)); + a.emit_cmp(Size::S64, Location::GPR(tmpg2), Location::GPR(tmpg1)); + a.emit_vminsd(src1, XMMOrMemory::XMM(src2), tmp_xmm1); + let label1 = a.get_label(); + let label2 = a.get_label(); + a.emit_jmp(Condition::NotEqual, label1); + a.emit_vmovapd(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); + a.emit_jmp(Condition::None, label2); + a.emit_label(label1); + // load float -0.0 + a.emit_mov( + Size::S64, + Location::Imm64((&NEG_ZERO as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov( + Size::S64, + Location::Memory(tmpg1, 0), + Location::XMM(tmp_xmm2), + ); + a.emit_label(label2); + a.emit_vcmpeqsd(src1, XMMOrMemory::XMM(src2), tmp_xmm3); + a.emit_vblendvpd(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); + a.emit_vcmpunordsd(src1, XMMOrMemory::XMM(src2), src1); + // load float canonical nan + a.emit_mov( + Size::S64, + Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_vblendvpd(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); + match ret { + Location::XMM(x) => { + a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(x)); + } + Location::Memory(_, _) | Location::GPR(_) => { + a.emit_mov(Size::S64, Location::XMM(src1), ret); + } + _ => unreachable!(), + } + + self.machine.release_temp_gpr(tmpg2); + self.machine.release_temp_gpr(tmpg1); + self.machine.release_temp_xmm(tmp2); + self.machine.release_temp_xmm(tmp1); + } Operator::F64Eq => Self::emit_fp_cmpop_avx( a, &mut self.machine, @@ -4155,7 +4715,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a| { a.emit_call_location(Location::GPR(GPR::RAX)); }, - ::std::iter::once(Location::Imm32(memory_index.index() as u32)), + iter::once(Location::Imm32(memory_index.index() as u32)), None, ); let ret = self.machine.acquire_locations( @@ -4194,8 +4754,8 @@ impl FunctionCodeGenerator for X64FunctionCode { |a| { a.emit_call_location(Location::GPR(GPR::RAX)); }, - ::std::iter::once(Location::Imm32(memory_index.index() as u32)) - .chain(::std::iter::once(param_pages)), + iter::once(Location::Imm32(memory_index.index() as u32)) + .chain(iter::once(param_pages)), None, ); diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 2e747f7ec..251868231 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -36,7 +36,7 @@ pub enum Size { S64, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[allow(dead_code)] pub enum XMMOrMemory { XMM(XMM), @@ -90,8 +90,8 @@ pub trait Emitter { fn emit_ror(&mut self, sz: Size, src: Location, dst: Location); fn emit_and(&mut self, sz: Size, src: Location, dst: Location); fn emit_or(&mut self, sz: Size, src: Location, dst: Location); - fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location); - fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location); + fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location); + fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location); fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_movzx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location); fn emit_movsx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location); @@ -105,6 +105,11 @@ pub trait Emitter { fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR); fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR); + fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory); + fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory); + fn emit_vxorps(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vxorpd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); @@ -136,6 +141,12 @@ pub trait Emitter { fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vcmpunordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vcmpunordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + + fn emit_vcmpordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vcmpordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); @@ -164,6 +175,9 @@ pub trait Emitter { fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM); fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM); + fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM); + fn emit_vblendvpd(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM); + fn emit_test_gpr_64(&mut self, reg: GPR); fn emit_ud2(&mut self); @@ -369,6 +383,14 @@ macro_rules! avx_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, Rx((x as u8))), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, Rx((x as u8))), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, Rx((x as u8))), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, Rx((x as u8))), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, Rx((x as u8))), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, Rx((x as u8))), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, Rx((x as u8))), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, Rx((x as u8))), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, Rx((x as u8))), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, Rx((x as u8))), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, Rx((x as u8))), }, XMMOrMemory::Memory(base, disp) => match src1 { XMM::XMM0 => dynasm!(self ; $ins Rx((dst as u8)), xmm0, [Rq((base as u8)) + disp]), @@ -379,6 +401,14 @@ macro_rules! avx_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, [Rq((base as u8)) + disp]), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, [Rq((base as u8)) + disp]), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, [Rq((base as u8)) + disp]), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, [Rq((base as u8)) + disp]), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, [Rq((base as u8)) + disp]), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, [Rq((base as u8)) + disp]), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, [Rq((base as u8)) + disp]), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, [Rq((base as u8)) + disp]), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, [Rq((base as u8)) + disp]), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, [Rq((base as u8)) + disp]), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, [Rq((base as u8)) + disp]), }, } } @@ -398,6 +428,14 @@ macro_rules! avx_i2f_64_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, Rq((x as u8))), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, Rq((x as u8))), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, Rq((x as u8))), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, Rq((x as u8))), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, Rq((x as u8))), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, Rq((x as u8))), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, Rq((x as u8))), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, Rq((x as u8))), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, Rq((x as u8))), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, Rq((x as u8))), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, Rq((x as u8))), }, GPROrMemory::Memory(base, disp) => match src1 { XMM::XMM0 => dynasm!(self ; $ins Rx((dst as u8)), xmm0, QWORD [Rq((base as u8)) + disp]), @@ -408,6 +446,14 @@ macro_rules! avx_i2f_64_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, QWORD [Rq((base as u8)) + disp]), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, QWORD [Rq((base as u8)) + disp]), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, QWORD [Rq((base as u8)) + disp]), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, QWORD [Rq((base as u8)) + disp]), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, QWORD [Rq((base as u8)) + disp]), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, QWORD [Rq((base as u8)) + disp]), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, QWORD [Rq((base as u8)) + disp]), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, QWORD [Rq((base as u8)) + disp]), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, QWORD [Rq((base as u8)) + disp]), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, QWORD [Rq((base as u8)) + disp]), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, QWORD [Rq((base as u8)) + disp]), }, } } @@ -427,6 +473,14 @@ macro_rules! avx_i2f_32_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, Rd((x as u8))), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, Rd((x as u8))), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, Rd((x as u8))), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, Rd((x as u8))), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, Rd((x as u8))), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, Rd((x as u8))), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, Rd((x as u8))), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, Rd((x as u8))), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, Rd((x as u8))), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, Rd((x as u8))), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, Rd((x as u8))), }, GPROrMemory::Memory(base, disp) => match src1 { XMM::XMM0 => dynasm!(self ; $ins Rx((dst as u8)), xmm0, DWORD [Rq((base as u8)) + disp]), @@ -437,6 +491,14 @@ macro_rules! avx_i2f_32_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, DWORD [Rq((base as u8)) + disp]), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, DWORD [Rq((base as u8)) + disp]), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, DWORD [Rq((base as u8)) + disp]), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, DWORD [Rq((base as u8)) + disp]), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, DWORD [Rq((base as u8)) + disp]), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, DWORD [Rq((base as u8)) + disp]), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, DWORD [Rq((base as u8)) + disp]), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, DWORD [Rq((base as u8)) + disp]), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, DWORD [Rq((base as u8)) + disp]), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, DWORD [Rq((base as u8)) + disp]), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, DWORD [Rq((base as u8)) + disp]), }, } } @@ -753,17 +815,17 @@ impl Emitter for Assembler { panic!("singlepass can't emit OR {:?} {:?} {:?}", sz, src, dst) }); } - fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { - binop_gpr_gpr!(lzcnt, self, sz, src, dst, { - binop_mem_gpr!(lzcnt, self, sz, src, dst, { - panic!("singlepass can't emit LZCNT {:?} {:?} {:?}", sz, src, dst) + fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) { + binop_gpr_gpr!(bsr, self, sz, src, dst, { + binop_mem_gpr!(bsr, self, sz, src, dst, { + panic!("singlepass can't emit BSR {:?} {:?} {:?}", sz, src, dst) }) }); } - fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { - binop_gpr_gpr!(tzcnt, self, sz, src, dst, { - binop_mem_gpr!(tzcnt, self, sz, src, dst, { - panic!("singlepass can't emit TZCNT {:?} {:?} {:?}", sz, src, dst) + fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) { + binop_gpr_gpr!(bsf, self, sz, src, dst, { + binop_mem_gpr!(bsf, self, sz, src, dst, { + panic!("singlepass can't emit BSF {:?} {:?} {:?}", sz, src, dst) }) }); } @@ -945,6 +1007,39 @@ impl Emitter for Assembler { dynasm!(self ; cmovae Rq(dst as u8), Rq(src as u8)); } + fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) { + match (src, dst) { + (XMMOrMemory::XMM(src), XMMOrMemory::XMM(dst)) => { + dynasm!(self ; movaps Rx(dst as u8), Rx(src as u8)) + } + (XMMOrMemory::Memory(base, disp), XMMOrMemory::XMM(dst)) => { + dynasm!(self ; movaps Rx(dst as u8), [Rq(base as u8) + disp]) + } + (XMMOrMemory::XMM(src), XMMOrMemory::Memory(base, disp)) => { + dynasm!(self ; movaps [Rq(base as u8) + disp], Rx(src as u8)) + } + _ => panic!("singlepass can't emit VMOVAPS {:?} {:?}", src, dst), + }; + } + + fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory) { + match (src, dst) { + (XMMOrMemory::XMM(src), XMMOrMemory::XMM(dst)) => { + dynasm!(self ; movapd Rx(dst as u8), Rx(src as u8)) + } + (XMMOrMemory::Memory(base, disp), XMMOrMemory::XMM(dst)) => { + dynasm!(self ; movapd Rx(dst as u8), [Rq(base as u8) + disp]) + } + (XMMOrMemory::XMM(src), XMMOrMemory::Memory(base, disp)) => { + dynasm!(self ; movapd [Rq(base as u8) + disp], Rx(src as u8)) + } + _ => panic!("singlepass can't emit VMOVAPD {:?} {:?}", src, dst), + }; + } + + avx_fn!(vxorps, emit_vxorps); + avx_fn!(vxorpd, emit_vxorpd); + avx_fn!(vaddss, emit_vaddss); avx_fn!(vaddsd, emit_vaddsd); @@ -981,6 +1076,12 @@ impl Emitter for Assembler { avx_fn!(vcmpgess, emit_vcmpgess); avx_fn!(vcmpgesd, emit_vcmpgesd); + avx_fn!(vcmpunordss, emit_vcmpunordss); + avx_fn!(vcmpunordsd, emit_vcmpunordsd); + + avx_fn!(vcmpordss, emit_vcmpordss); + avx_fn!(vcmpordsd, emit_vcmpordsd); + avx_fn!(vsqrtss, emit_vsqrtss); avx_fn!(vsqrtsd, emit_vsqrtsd); @@ -1001,6 +1102,28 @@ impl Emitter for Assembler { avx_i2f_64_fn!(vcvtsi2ss, emit_vcvtsi2ss_64); avx_i2f_64_fn!(vcvtsi2sd, emit_vcvtsi2sd_64); + fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) { + match src2 { + XMMOrMemory::XMM(src2) => { + dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), Rx(src2 as u8), Rx(src1 as u8)) + } + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), [Rq(base as u8) + disp], Rx(src1 as u8)) + } + } + } + + fn emit_vblendvpd(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) { + match src2 { + XMMOrMemory::XMM(src2) => { + dynasm!(self ; vblendvpd Rx(dst as u8), Rx(mask as u8), Rx(src2 as u8), Rx(src1 as u8)) + } + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; vblendvpd Rx(dst as u8), Rx(mask as u8), [Rq(base as u8) + disp], Rx(src1 as u8)) + } + } + } + fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; ucomiss Rx(dst as u8), Rx(x as u8)), diff --git a/lib/singlepass-backend/src/machine.rs b/lib/singlepass-backend/src/machine.rs index 727b577d7..017ba1270 100644 --- a/lib/singlepass-backend/src/machine.rs +++ b/lib/singlepass-backend/src/machine.rs @@ -1,9 +1,10 @@ use crate::emitter_x64::*; use smallvec::SmallVec; use std::collections::HashSet; -use wasmer_runtime_core::state::x64::X64Register; -use wasmer_runtime_core::state::*; -use wasmparser::Type as WpType; +use wasmer_runtime_core::{ + state::{x64::X64Register, *}, + wasmparser::Type as WpType, +}; struct MachineStackOffset(usize); diff --git a/lib/spectests/Cargo.toml b/lib/spectests/Cargo.toml index 6f62ab098..88df56329 100644 --- a/lib/spectests/Cargo.toml +++ b/lib/spectests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-spectests" -version = "0.8.0" +version = "0.9.0" description = "Wasmer spectests library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,10 +9,10 @@ edition = "2018" [dependencies] glob = "0.3" -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.8.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.8.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.9.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } [build-dependencies] wabt = "0.9.1" diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 56c6a2d56..c77766939 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -24,7 +24,6 @@ clif:skip:simd_binaryen.wast:* # SIMD not implemented # linking.wast:387,388 appear to be related to WABT issue: https://github.com/pepyakin/wabt-rs/issues/51 -clif:fail:globals.wast:243 # AssertInvalid - Should be invalid clif:fail:linking.wast:137 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" clif:fail:linking.wast:139 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" clif:fail:linking.wast:142 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" @@ -33,7 +32,6 @@ clif:fail:linking.wast:147 # AssertTrap - expected trap, got Runtime:Error "unkn clif:fail:linking.wast:149 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883037 - illegal instruction" clif:fail:linking.wast:185 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" clif:fail:linking.wast:187 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" -clif:fail:linking.wast:387 # AssertReturn - result I32(0) ("0x0") does not match expected I32(104) ("0x68") clif:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: WebAssembly trap occurred during runtime: `call_indirect` out-of-bounds # clif:skip:skip-stack-guard-page.wast:2 # Slow test @@ -84,6 +82,7 @@ clif:fail:data.wast:227:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:258:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:273:windows # AssertUnlinkable - caught panic Any clif:fail:start.wast:92:windows # Module - caught panic Any +clif:skip:start.wast:98:windows clif:fail:align.wast:3:windows # Module - caught panic Any clif:fail:align.wast:4:windows # Module - caught panic Any @@ -265,577 +264,12 @@ clif:fail:data.wast:266:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:186:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:194:windows # AssertUnlinkable - caught panic Any -# LLVM bug with min/max over NaNs -llvm:skip:f32.wast:1651 -llvm:skip:f32.wast:1652 -llvm:skip:f32.wast:1653 -llvm:skip:f32.wast:1654 -llvm:skip:f32.wast:1655 -llvm:skip:f32.wast:1656 -llvm:skip:f32.wast:1657 -llvm:skip:f32.wast:1658 -llvm:skip:f32.wast:1691 -llvm:skip:f32.wast:1692 -llvm:skip:f32.wast:1693 -llvm:skip:f32.wast:1694 -llvm:skip:f32.wast:1695 -llvm:skip:f32.wast:1696 -llvm:skip:f32.wast:1697 -llvm:skip:f32.wast:1698 -llvm:skip:f32.wast:1731 -llvm:skip:f32.wast:1732 -llvm:skip:f32.wast:1733 -llvm:skip:f32.wast:1734 -llvm:skip:f32.wast:1735 -llvm:skip:f32.wast:1736 -llvm:skip:f32.wast:1737 -llvm:skip:f32.wast:1738 -llvm:skip:f32.wast:1771 -llvm:skip:f32.wast:1772 -llvm:skip:f32.wast:1773 -llvm:skip:f32.wast:1774 -llvm:skip:f32.wast:1775 -llvm:skip:f32.wast:1776 -llvm:skip:f32.wast:1777 -llvm:skip:f32.wast:1778 -llvm:skip:f32.wast:1811 -llvm:skip:f32.wast:1812 -llvm:skip:f32.wast:1813 -llvm:skip:f32.wast:1814 -llvm:skip:f32.wast:1815 -llvm:skip:f32.wast:1816 -llvm:skip:f32.wast:1817 -llvm:skip:f32.wast:1818 -llvm:skip:f32.wast:1851 -llvm:skip:f32.wast:1852 -llvm:skip:f32.wast:1853 -llvm:skip:f32.wast:1854 -llvm:skip:f32.wast:1855 -llvm:skip:f32.wast:1856 -llvm:skip:f32.wast:1857 -llvm:skip:f32.wast:1858 -llvm:skip:f32.wast:1891 -llvm:skip:f32.wast:1892 -llvm:skip:f32.wast:1893 -llvm:skip:f32.wast:1894 -llvm:skip:f32.wast:1895 -llvm:skip:f32.wast:1896 -llvm:skip:f32.wast:1897 -llvm:skip:f32.wast:1898 -llvm:skip:f32.wast:1931 -llvm:skip:f32.wast:1932 -llvm:skip:f32.wast:1933 -llvm:skip:f32.wast:1934 -llvm:skip:f32.wast:1935 -llvm:skip:f32.wast:1936 -llvm:skip:f32.wast:1937 -llvm:skip:f32.wast:1938 -llvm:skip:f32.wast:1939 -llvm:skip:f32.wast:1940 -llvm:skip:f32.wast:1941 -llvm:skip:f32.wast:1942 -llvm:skip:f32.wast:1943 -llvm:skip:f32.wast:1944 -llvm:skip:f32.wast:1945 -llvm:skip:f32.wast:1946 -llvm:skip:f32.wast:1947 -llvm:skip:f32.wast:1948 -llvm:skip:f32.wast:1949 -llvm:skip:f32.wast:1950 -llvm:skip:f32.wast:1951 -llvm:skip:f32.wast:1952 -llvm:skip:f32.wast:1953 -llvm:skip:f32.wast:1954 -llvm:skip:f32.wast:1955 -llvm:skip:f32.wast:1956 -llvm:skip:f32.wast:1957 -llvm:skip:f32.wast:1958 -llvm:skip:f32.wast:1959 -llvm:skip:f32.wast:1960 -llvm:skip:f32.wast:1961 -llvm:skip:f32.wast:1962 -llvm:skip:f32.wast:1963 -llvm:skip:f32.wast:1964 -llvm:skip:f32.wast:1965 -llvm:skip:f32.wast:1966 -llvm:skip:f32.wast:1967 -llvm:skip:f32.wast:1968 -llvm:skip:f32.wast:1969 -llvm:skip:f32.wast:1970 -llvm:skip:f32.wast:1971 -llvm:skip:f32.wast:1972 -llvm:skip:f32.wast:1973 -llvm:skip:f32.wast:1974 -llvm:skip:f32.wast:1975 -llvm:skip:f32.wast:1976 -llvm:skip:f32.wast:1977 -llvm:skip:f32.wast:1978 -llvm:skip:f32.wast:1979 -llvm:skip:f32.wast:1980 -llvm:skip:f32.wast:1981 -llvm:skip:f32.wast:1982 -llvm:skip:f32.wast:1983 -llvm:skip:f32.wast:1984 -llvm:skip:f32.wast:1985 -llvm:skip:f32.wast:1986 -llvm:skip:f32.wast:1987 -llvm:skip:f32.wast:1988 -llvm:skip:f32.wast:1989 -llvm:skip:f32.wast:1990 -llvm:skip:f32.wast:1991 -llvm:skip:f32.wast:1992 -llvm:skip:f32.wast:1993 -llvm:skip:f32.wast:1994 -llvm:skip:f32.wast:1995 -llvm:skip:f32.wast:1996 -llvm:skip:f32.wast:1997 -llvm:skip:f32.wast:1998 -llvm:skip:f32.wast:1999 -llvm:skip:f32.wast:2000 -llvm:skip:f32.wast:2001 -llvm:skip:f32.wast:2002 -llvm:skip:f32.wast:2005 -llvm:skip:f32.wast:2006 -llvm:skip:f32.wast:2009 -llvm:skip:f32.wast:2010 -llvm:skip:f32.wast:2013 -llvm:skip:f32.wast:2014 -llvm:skip:f32.wast:2017 -llvm:skip:f32.wast:2018 -llvm:skip:f32.wast:2051 -llvm:skip:f32.wast:2052 -llvm:skip:f32.wast:2053 -llvm:skip:f32.wast:2054 -llvm:skip:f32.wast:2055 -llvm:skip:f32.wast:2056 -llvm:skip:f32.wast:2057 -llvm:skip:f32.wast:2058 -llvm:skip:f32.wast:2091 -llvm:skip:f32.wast:2092 -llvm:skip:f32.wast:2093 -llvm:skip:f32.wast:2094 -llvm:skip:f32.wast:2095 -llvm:skip:f32.wast:2096 -llvm:skip:f32.wast:2097 -llvm:skip:f32.wast:2098 -llvm:skip:f32.wast:2131 -llvm:skip:f32.wast:2132 -llvm:skip:f32.wast:2133 -llvm:skip:f32.wast:2134 -llvm:skip:f32.wast:2135 -llvm:skip:f32.wast:2136 -llvm:skip:f32.wast:2137 -llvm:skip:f32.wast:2138 -llvm:skip:f32.wast:2171 -llvm:skip:f32.wast:2172 -llvm:skip:f32.wast:2173 -llvm:skip:f32.wast:2174 -llvm:skip:f32.wast:2175 -llvm:skip:f32.wast:2176 -llvm:skip:f32.wast:2177 -llvm:skip:f32.wast:2178 -llvm:skip:f32.wast:2211 -llvm:skip:f32.wast:2212 -llvm:skip:f32.wast:2213 -llvm:skip:f32.wast:2214 -llvm:skip:f32.wast:2215 -llvm:skip:f32.wast:2216 -llvm:skip:f32.wast:2217 -llvm:skip:f32.wast:2218 -llvm:skip:f32.wast:2251 -llvm:skip:f32.wast:2252 -llvm:skip:f32.wast:2253 -llvm:skip:f32.wast:2254 -llvm:skip:f32.wast:2255 -llvm:skip:f32.wast:2256 -llvm:skip:f32.wast:2257 -llvm:skip:f32.wast:2258 -llvm:skip:f32.wast:2291 -llvm:skip:f32.wast:2292 -llvm:skip:f32.wast:2293 -llvm:skip:f32.wast:2294 -llvm:skip:f32.wast:2295 -llvm:skip:f32.wast:2296 -llvm:skip:f32.wast:2297 -llvm:skip:f32.wast:2298 -llvm:skip:f32.wast:2331 -llvm:skip:f32.wast:2332 -llvm:skip:f32.wast:2333 -llvm:skip:f32.wast:2334 -llvm:skip:f32.wast:2335 -llvm:skip:f32.wast:2336 -llvm:skip:f32.wast:2337 -llvm:skip:f32.wast:2338 -llvm:skip:f32.wast:2339 -llvm:skip:f32.wast:2340 -llvm:skip:f32.wast:2341 -llvm:skip:f32.wast:2342 -llvm:skip:f32.wast:2343 -llvm:skip:f32.wast:2344 -llvm:skip:f32.wast:2345 -llvm:skip:f32.wast:2346 -llvm:skip:f32.wast:2347 -llvm:skip:f32.wast:2348 -llvm:skip:f32.wast:2349 -llvm:skip:f32.wast:2350 -llvm:skip:f32.wast:2351 -llvm:skip:f32.wast:2352 -llvm:skip:f32.wast:2353 -llvm:skip:f32.wast:2354 -llvm:skip:f32.wast:2355 -llvm:skip:f32.wast:2356 -llvm:skip:f32.wast:2357 -llvm:skip:f32.wast:2358 -llvm:skip:f32.wast:2359 -llvm:skip:f32.wast:2360 -llvm:skip:f32.wast:2361 -llvm:skip:f32.wast:2362 -llvm:skip:f32.wast:2363 -llvm:skip:f32.wast:2364 -llvm:skip:f32.wast:2365 -llvm:skip:f32.wast:2366 -llvm:skip:f32.wast:2367 -llvm:skip:f32.wast:2368 -llvm:skip:f32.wast:2369 -llvm:skip:f32.wast:2370 -llvm:skip:f32.wast:2371 -llvm:skip:f32.wast:2372 -llvm:skip:f32.wast:2373 -llvm:skip:f32.wast:2374 -llvm:skip:f32.wast:2375 -llvm:skip:f32.wast:2376 -llvm:skip:f32.wast:2377 -llvm:skip:f32.wast:2378 -llvm:skip:f32.wast:2379 -llvm:skip:f32.wast:2380 -llvm:skip:f32.wast:2381 -llvm:skip:f32.wast:2382 -llvm:skip:f32.wast:2383 -llvm:skip:f32.wast:2384 -llvm:skip:f32.wast:2385 -llvm:skip:f32.wast:2386 -llvm:skip:f32.wast:2387 -llvm:skip:f32.wast:2388 -llvm:skip:f32.wast:2389 -llvm:skip:f32.wast:2390 -llvm:skip:f32.wast:2391 -llvm:skip:f32.wast:2392 -llvm:skip:f32.wast:2393 -llvm:skip:f32.wast:2394 -llvm:skip:f32.wast:2395 -llvm:skip:f32.wast:2396 -llvm:skip:f32.wast:2397 -llvm:skip:f32.wast:2398 -llvm:skip:f32.wast:2399 -llvm:skip:f32.wast:2400 -llvm:skip:f32.wast:2401 -llvm:skip:f32.wast:2402 -llvm:skip:f32.wast:2403 -llvm:skip:f32.wast:2404 -llvm:skip:f32.wast:2405 -llvm:skip:f32.wast:2406 -llvm:skip:f32.wast:2409 -llvm:skip:f32.wast:2410 -llvm:skip:f32.wast:2413 -llvm:skip:f32.wast:2414 -llvm:skip:f32.wast:2417 -llvm:skip:f32.wast:2418 -llvm:skip:f64.wast:1651 -llvm:skip:f64.wast:1652 -llvm:skip:f64.wast:1653 -llvm:skip:f64.wast:1654 -llvm:skip:f64.wast:1655 -llvm:skip:f64.wast:1656 -llvm:skip:f64.wast:1657 -llvm:skip:f64.wast:1658 -llvm:skip:f64.wast:1691 -llvm:skip:f64.wast:1692 -llvm:skip:f64.wast:1693 -llvm:skip:f64.wast:1694 -llvm:skip:f64.wast:1695 -llvm:skip:f64.wast:1696 -llvm:skip:f64.wast:1697 -llvm:skip:f64.wast:1698 -llvm:skip:f64.wast:1731 -llvm:skip:f64.wast:1732 -llvm:skip:f64.wast:1733 -llvm:skip:f64.wast:1734 -llvm:skip:f64.wast:1735 -llvm:skip:f64.wast:1736 -llvm:skip:f64.wast:1737 -llvm:skip:f64.wast:1738 -llvm:skip:f64.wast:1771 -llvm:skip:f64.wast:1772 -llvm:skip:f64.wast:1773 -llvm:skip:f64.wast:1774 -llvm:skip:f64.wast:1775 -llvm:skip:f64.wast:1776 -llvm:skip:f64.wast:1777 -llvm:skip:f64.wast:1778 -llvm:skip:f64.wast:1811 -llvm:skip:f64.wast:1812 -llvm:skip:f64.wast:1813 -llvm:skip:f64.wast:1814 -llvm:skip:f64.wast:1815 -llvm:skip:f64.wast:1816 -llvm:skip:f64.wast:1817 -llvm:skip:f64.wast:1818 -llvm:skip:f64.wast:1851 -llvm:skip:f64.wast:1852 -llvm:skip:f64.wast:1853 -llvm:skip:f64.wast:1854 -llvm:skip:f64.wast:1855 -llvm:skip:f64.wast:1856 -llvm:skip:f64.wast:1857 -llvm:skip:f64.wast:1858 -llvm:skip:f64.wast:1891 -llvm:skip:f64.wast:1892 -llvm:skip:f64.wast:1893 -llvm:skip:f64.wast:1894 -llvm:skip:f64.wast:1895 -llvm:skip:f64.wast:1896 -llvm:skip:f64.wast:1897 -llvm:skip:f64.wast:1898 -llvm:skip:f64.wast:1931 -llvm:skip:f64.wast:1932 -llvm:skip:f64.wast:1933 -llvm:skip:f64.wast:1934 -llvm:skip:f64.wast:1935 -llvm:skip:f64.wast:1936 -llvm:skip:f64.wast:1937 -llvm:skip:f64.wast:1938 -llvm:skip:f64.wast:1939 -llvm:skip:f64.wast:1940 -llvm:skip:f64.wast:1941 -llvm:skip:f64.wast:1942 -llvm:skip:f64.wast:1943 -llvm:skip:f64.wast:1944 -llvm:skip:f64.wast:1945 -llvm:skip:f64.wast:1946 -llvm:skip:f64.wast:1947 -llvm:skip:f64.wast:1948 -llvm:skip:f64.wast:1949 -llvm:skip:f64.wast:1950 -llvm:skip:f64.wast:1951 -llvm:skip:f64.wast:1952 -llvm:skip:f64.wast:1953 -llvm:skip:f64.wast:1954 -llvm:skip:f64.wast:1955 -llvm:skip:f64.wast:1956 -llvm:skip:f64.wast:1957 -llvm:skip:f64.wast:1958 -llvm:skip:f64.wast:1959 -llvm:skip:f64.wast:1960 -llvm:skip:f64.wast:1961 -llvm:skip:f64.wast:1962 -llvm:skip:f64.wast:1963 -llvm:skip:f64.wast:1964 -llvm:skip:f64.wast:1965 -llvm:skip:f64.wast:1966 -llvm:skip:f64.wast:1967 -llvm:skip:f64.wast:1968 -llvm:skip:f64.wast:1969 -llvm:skip:f64.wast:1970 -llvm:skip:f64.wast:1971 -llvm:skip:f64.wast:1972 -llvm:skip:f64.wast:1973 -llvm:skip:f64.wast:1974 -llvm:skip:f64.wast:1975 -llvm:skip:f64.wast:1976 -llvm:skip:f64.wast:1977 -llvm:skip:f64.wast:1978 -llvm:skip:f64.wast:1979 -llvm:skip:f64.wast:1980 -llvm:skip:f64.wast:1981 -llvm:skip:f64.wast:1982 -llvm:skip:f64.wast:1983 -llvm:skip:f64.wast:1984 -llvm:skip:f64.wast:1985 -llvm:skip:f64.wast:1986 -llvm:skip:f64.wast:1987 -llvm:skip:f64.wast:1988 -llvm:skip:f64.wast:1989 -llvm:skip:f64.wast:1990 -llvm:skip:f64.wast:1991 -llvm:skip:f64.wast:1992 -llvm:skip:f64.wast:1993 -llvm:skip:f64.wast:1994 -llvm:skip:f64.wast:1995 -llvm:skip:f64.wast:1996 -llvm:skip:f64.wast:1997 -llvm:skip:f64.wast:1998 -llvm:skip:f64.wast:1999 -llvm:skip:f64.wast:2000 -llvm:skip:f64.wast:2001 -llvm:skip:f64.wast:2002 -llvm:skip:f64.wast:2005 -llvm:skip:f64.wast:2006 -llvm:skip:f64.wast:2009 -llvm:skip:f64.wast:2010 -llvm:skip:f64.wast:2013 -llvm:skip:f64.wast:2014 -llvm:skip:f64.wast:2017 -llvm:skip:f64.wast:2018 -llvm:skip:f64.wast:2051 -llvm:skip:f64.wast:2052 -llvm:skip:f64.wast:2053 -llvm:skip:f64.wast:2054 -llvm:skip:f64.wast:2055 -llvm:skip:f64.wast:2056 -llvm:skip:f64.wast:2057 -llvm:skip:f64.wast:2058 -llvm:skip:f64.wast:2091 -llvm:skip:f64.wast:2092 -llvm:skip:f64.wast:2093 -llvm:skip:f64.wast:2094 -llvm:skip:f64.wast:2095 -llvm:skip:f64.wast:2096 -llvm:skip:f64.wast:2097 -llvm:skip:f64.wast:2098 -llvm:skip:f64.wast:2131 -llvm:skip:f64.wast:2132 -llvm:skip:f64.wast:2133 -llvm:skip:f64.wast:2134 -llvm:skip:f64.wast:2135 -llvm:skip:f64.wast:2136 -llvm:skip:f64.wast:2137 -llvm:skip:f64.wast:2138 -llvm:skip:f64.wast:2171 -llvm:skip:f64.wast:2172 -llvm:skip:f64.wast:2173 -llvm:skip:f64.wast:2174 -llvm:skip:f64.wast:2175 -llvm:skip:f64.wast:2176 -llvm:skip:f64.wast:2177 -llvm:skip:f64.wast:2178 -llvm:skip:f64.wast:2211 -llvm:skip:f64.wast:2212 -llvm:skip:f64.wast:2213 -llvm:skip:f64.wast:2214 -llvm:skip:f64.wast:2215 -llvm:skip:f64.wast:2216 -llvm:skip:f64.wast:2217 -llvm:skip:f64.wast:2218 -llvm:skip:f64.wast:2251 -llvm:skip:f64.wast:2252 -llvm:skip:f64.wast:2253 -llvm:skip:f64.wast:2254 -llvm:skip:f64.wast:2255 -llvm:skip:f64.wast:2256 -llvm:skip:f64.wast:2257 -llvm:skip:f64.wast:2258 -llvm:skip:f64.wast:2291 -llvm:skip:f64.wast:2292 -llvm:skip:f64.wast:2293 -llvm:skip:f64.wast:2294 -llvm:skip:f64.wast:2295 -llvm:skip:f64.wast:2296 -llvm:skip:f64.wast:2297 -llvm:skip:f64.wast:2298 -llvm:skip:f64.wast:2331 -llvm:skip:f64.wast:2332 -llvm:skip:f64.wast:2333 -llvm:skip:f64.wast:2334 -llvm:skip:f64.wast:2335 -llvm:skip:f64.wast:2336 -llvm:skip:f64.wast:2337 -llvm:skip:f64.wast:2338 -llvm:skip:f64.wast:2339 -llvm:skip:f64.wast:2340 -llvm:skip:f64.wast:2341 -llvm:skip:f64.wast:2342 -llvm:skip:f64.wast:2343 -llvm:skip:f64.wast:2344 -llvm:skip:f64.wast:2345 -llvm:skip:f64.wast:2346 -llvm:skip:f64.wast:2347 -llvm:skip:f64.wast:2348 -llvm:skip:f64.wast:2349 -llvm:skip:f64.wast:2350 -llvm:skip:f64.wast:2351 -llvm:skip:f64.wast:2352 -llvm:skip:f64.wast:2353 -llvm:skip:f64.wast:2354 -llvm:skip:f64.wast:2355 -llvm:skip:f64.wast:2356 -llvm:skip:f64.wast:2357 -llvm:skip:f64.wast:2358 -llvm:skip:f64.wast:2359 -llvm:skip:f64.wast:2360 -llvm:skip:f64.wast:2361 -llvm:skip:f64.wast:2362 -llvm:skip:f64.wast:2363 -llvm:skip:f64.wast:2364 -llvm:skip:f64.wast:2365 -llvm:skip:f64.wast:2366 -llvm:skip:f64.wast:2367 -llvm:skip:f64.wast:2368 -llvm:skip:f64.wast:2369 -llvm:skip:f64.wast:2370 -llvm:skip:f64.wast:2371 -llvm:skip:f64.wast:2372 -llvm:skip:f64.wast:2373 -llvm:skip:f64.wast:2374 -llvm:skip:f64.wast:2375 -llvm:skip:f64.wast:2376 -llvm:skip:f64.wast:2377 -llvm:skip:f64.wast:2378 -llvm:skip:f64.wast:2379 -llvm:skip:f64.wast:2380 -llvm:skip:f64.wast:2381 -llvm:skip:f64.wast:2382 -llvm:skip:f64.wast:2383 -llvm:skip:f64.wast:2384 -llvm:skip:f64.wast:2385 -llvm:skip:f64.wast:2386 -llvm:skip:f64.wast:2387 -llvm:skip:f64.wast:2388 -llvm:skip:f64.wast:2389 -llvm:skip:f64.wast:2390 -llvm:skip:f64.wast:2391 -llvm:skip:f64.wast:2392 -llvm:skip:f64.wast:2393 -llvm:skip:f64.wast:2394 -llvm:skip:f64.wast:2395 -llvm:skip:f64.wast:2396 -llvm:skip:f64.wast:2397 -llvm:skip:f64.wast:2398 -llvm:skip:f64.wast:2399 -llvm:skip:f64.wast:2400 -llvm:skip:f64.wast:2401 -llvm:skip:f64.wast:2402 -llvm:skip:f64.wast:2405 -llvm:skip:f64.wast:2406 -llvm:skip:f64.wast:2409 -llvm:skip:f64.wast:2410 -llvm:skip:f64.wast:2413 -llvm:skip:f64.wast:2414 -llvm:skip:f64.wast:2417 -llvm:skip:f64.wast:2418 - # LLVM -llvm:skip:br_table.wast:1255 -llvm:skip:imports.wast:391 # Running forever -llvm:skip:imports.wast:402 # Running forever -llvm:skip:call.wast:273 # Spec running forever -llvm:skip:call_indirect.wast:556 # Spec running forever -llvm:skip:call_indirect.wast:557 # Spec running forever -llvm:skip:fac.wast:89 # Spec running forever -llvm:skip:skip-stack-guard-page.wast:* # Spec running forever or (signal: 4, SIGILL: illegal instruction) -llvm:skip:linking.wast:236 # terminating with uncaught exception of type WasmTrap -llvm:skip:linking.wast:248 # terminating with uncaught exception of type WasmTrap - llvm:fail:f32.wast:1621 # AssertReturn - result F32(0) ("0x0") does not match expected F32(2147483648) ("0x80000000") llvm:fail:f32.wast:2020 # AssertReturn - result F32(2147483648) ("0x80000000") does not match expected F32(0) ("0x0") llvm:fail:f64.wast:1621 # AssertReturn - result F64(0) ("0x0") does not match expected F64(9223372036854775808) ("0x8000000000000000") llvm:fail:f64.wast:2020 # AssertReturn - result F64(9223372036854775808) ("0x8000000000000000") does not match expected F64(0) ("0x0") -llvm:fail:i32.wast:243 # AssertReturn - result I32(283816271) ("0x10eab14f") does not match expected I32(32) ("0x20") -llvm:fail:i32.wast:252 # AssertReturn - result I32(283816288) ("0x10eab160") does not match expected I32(32) ("0x20") -llvm:fail:i64.wast:243 # AssertReturn - result I64(4578783727) ("0x110eab1ef") does not match expected I64(64) ("0x40") -llvm:fail:i64.wast:252 # AssertReturn - result I64(4578783712) ("0x110eab1e0") does not match expected I64(64) ("0x40") -llvm:fail:linking.wast:387 # AssertReturn - result I32(0) ("0x0") does not match expected I32(104) ("0x68") llvm:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: WebAssembly trap occurred during runtime: incorrect `call_indirect` signature -llvm:fail:load.wast:201 # AssertReturn - result I32(285315103) ("0x1101901f") does not match expected I32(32) ("0x20") # LLVM Windows llvm:skip:address.wast:*:windows @@ -1030,426 +464,6 @@ singlepass:fail:conversions.wast:240 # AssertTrap - expected trap, got Runtime:E singlepass:fail:conversions.wast:241 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:242 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:elem.wast:353 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:f32.wast:1620 # AssertReturn - result F32(0) ("0x0") does not match expected F32(2147483648) ("0x80000000") -singlepass:fail:f32.wast:1652 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1654 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1656 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1658 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1692 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1694 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1696 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1698 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1732 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1734 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1736 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1738 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1772 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1774 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1776 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1778 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1812 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1814 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1816 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1818 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1852 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1854 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1856 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1858 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1892 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1894 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1896 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1898 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1932 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1934 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1936 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1938 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1939 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.0) -singlepass:fail:f32.wast:1940 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.0) -singlepass:fail:f32.wast:1941 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.0) -singlepass:fail:f32.wast:1942 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.0) -singlepass:fail:f32.wast:1943 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.0) -singlepass:fail:f32.wast:1944 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.0) -singlepass:fail:f32.wast:1945 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.0) -singlepass:fail:f32.wast:1946 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.0) -singlepass:fail:f32.wast:1947 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1948 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1949 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1950 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1951 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1952 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1953 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1954 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1955 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1956 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1957 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1958 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1959 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1960 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1961 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1962 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1963 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.5) -singlepass:fail:f32.wast:1964 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.5) -singlepass:fail:f32.wast:1965 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.5) -singlepass:fail:f32.wast:1966 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.5) -singlepass:fail:f32.wast:1967 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.5) -singlepass:fail:f32.wast:1968 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.5) -singlepass:fail:f32.wast:1969 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.5) -singlepass:fail:f32.wast:1970 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.5) -singlepass:fail:f32.wast:1971 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-1.0) -singlepass:fail:f32.wast:1972 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-1.0) -singlepass:fail:f32.wast:1973 # "AssertReturnCanonicalNan" - value is not canonical nan F32(1.0) -singlepass:fail:f32.wast:1974 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(1.0) -singlepass:fail:f32.wast:1975 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-1.0) -singlepass:fail:f32.wast:1976 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-1.0) -singlepass:fail:f32.wast:1977 # "AssertReturnCanonicalNan" - value is not canonical nan F32(1.0) -singlepass:fail:f32.wast:1978 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(1.0) -singlepass:fail:f32.wast:1979 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-6.2831855) -singlepass:fail:f32.wast:1980 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-6.2831855) -singlepass:fail:f32.wast:1981 # "AssertReturnCanonicalNan" - value is not canonical nan F32(6.2831855) -singlepass:fail:f32.wast:1982 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(6.2831855) -singlepass:fail:f32.wast:1983 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-6.2831855) -singlepass:fail:f32.wast:1984 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-6.2831855) -singlepass:fail:f32.wast:1985 # "AssertReturnCanonicalNan" - value is not canonical nan F32(6.2831855) -singlepass:fail:f32.wast:1986 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(6.2831855) -singlepass:fail:f32.wast:1987 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1988 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1989 # "AssertReturnCanonicalNan" - value is not canonical nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1990 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1991 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1992 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1993 # "AssertReturnCanonicalNan" - value is not canonical nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1994 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1995 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-inf) -singlepass:fail:f32.wast:1996 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-inf) -singlepass:fail:f32.wast:1997 # "AssertReturnCanonicalNan" - value is not canonical nan F32(inf) -singlepass:fail:f32.wast:1998 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(inf) -singlepass:fail:f32.wast:1999 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-inf) -singlepass:fail:f32.wast:2000 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-inf) -singlepass:fail:f32.wast:2001 # "AssertReturnCanonicalNan" - value is not canonical nan F32(inf) -singlepass:fail:f32.wast:2002 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(inf) -singlepass:fail:f32.wast:2005 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2006 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2009 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2010 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2013 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2014 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2017 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2018 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2021 # AssertReturn - result F32(2147483648) ("0x80000000") does not match expected F32(0) ("0x0") -singlepass:fail:f32.wast:2052 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2054 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2056 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2058 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2092 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2094 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2096 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2098 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2132 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2134 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2136 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2138 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2172 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2174 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2176 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2178 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2212 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2214 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2216 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2218 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2252 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2254 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2256 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2258 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2292 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2294 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2296 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2298 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2332 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2334 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2336 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2338 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2339 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.0) -singlepass:fail:f32.wast:2340 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.0) -singlepass:fail:f32.wast:2341 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.0) -singlepass:fail:f32.wast:2342 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.0) -singlepass:fail:f32.wast:2343 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.0) -singlepass:fail:f32.wast:2344 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.0) -singlepass:fail:f32.wast:2345 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.0) -singlepass:fail:f32.wast:2346 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.0) -singlepass:fail:f32.wast:2347 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2348 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2349 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2350 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2351 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2352 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2353 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2354 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2355 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2356 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2357 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2358 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2359 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2360 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2361 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2362 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2363 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.5) -singlepass:fail:f32.wast:2364 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.5) -singlepass:fail:f32.wast:2365 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.5) -singlepass:fail:f32.wast:2366 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.5) -singlepass:fail:f32.wast:2367 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.5) -singlepass:fail:f32.wast:2368 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.5) -singlepass:fail:f32.wast:2369 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.5) -singlepass:fail:f32.wast:2370 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.5) -singlepass:fail:f32.wast:2371 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-1.0) -singlepass:fail:f32.wast:2372 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-1.0) -singlepass:fail:f32.wast:2373 # "AssertReturnCanonicalNan" - value is not canonical nan F32(1.0) -singlepass:fail:f32.wast:2374 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(1.0) -singlepass:fail:f32.wast:2375 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-1.0) -singlepass:fail:f32.wast:2376 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-1.0) -singlepass:fail:f32.wast:2377 # "AssertReturnCanonicalNan" - value is not canonical nan F32(1.0) -singlepass:fail:f32.wast:2378 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(1.0) -singlepass:fail:f32.wast:2379 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-6.2831855) -singlepass:fail:f32.wast:2380 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-6.2831855) -singlepass:fail:f32.wast:2381 # "AssertReturnCanonicalNan" - value is not canonical nan F32(6.2831855) -singlepass:fail:f32.wast:2382 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(6.2831855) -singlepass:fail:f32.wast:2383 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-6.2831855) -singlepass:fail:f32.wast:2384 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-6.2831855) -singlepass:fail:f32.wast:2385 # "AssertReturnCanonicalNan" - value is not canonical nan F32(6.2831855) -singlepass:fail:f32.wast:2386 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(6.2831855) -singlepass:fail:f32.wast:2387 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2388 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2389 # "AssertReturnCanonicalNan" - value is not canonical nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2390 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2391 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2392 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2393 # "AssertReturnCanonicalNan" - value is not canonical nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2394 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2395 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-inf) -singlepass:fail:f32.wast:2396 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-inf) -singlepass:fail:f32.wast:2397 # "AssertReturnCanonicalNan" - value is not canonical nan F32(inf) -singlepass:fail:f32.wast:2398 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(inf) -singlepass:fail:f32.wast:2399 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-inf) -singlepass:fail:f32.wast:2400 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-inf) -singlepass:fail:f32.wast:2401 # "AssertReturnCanonicalNan" - value is not canonical nan F32(inf) -singlepass:fail:f32.wast:2402 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(inf) -singlepass:fail:f32.wast:2405 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2406 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2409 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2410 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2413 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2414 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2417 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2418 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f64.wast:1620 # AssertReturn - result F64(0) ("0x0") does not match expected F64(9223372036854775808) ("0x8000000000000000") -singlepass:fail:f64.wast:1652 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1654 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1656 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1658 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1692 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1694 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1696 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1698 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1732 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1734 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1736 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1738 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1772 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1774 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1776 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1778 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1812 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1814 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1816 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1818 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1852 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1854 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1856 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1858 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1892 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1894 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1896 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1898 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1932 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1934 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1936 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1938 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1939 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.0) -singlepass:fail:f64.wast:1940 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.0) -singlepass:fail:f64.wast:1941 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.0) -singlepass:fail:f64.wast:1942 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.0) -singlepass:fail:f64.wast:1943 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.0) -singlepass:fail:f64.wast:1944 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.0) -singlepass:fail:f64.wast:1945 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.0) -singlepass:fail:f64.wast:1946 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.0) -singlepass:fail:f64.wast:1947 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1948 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1949 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1950 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1951 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1952 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1953 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1954 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1955 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1956 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1957 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1958 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1959 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1960 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1961 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1962 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1963 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.5) -singlepass:fail:f64.wast:1964 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.5) -singlepass:fail:f64.wast:1965 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.5) -singlepass:fail:f64.wast:1966 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.5) -singlepass:fail:f64.wast:1967 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.5) -singlepass:fail:f64.wast:1968 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.5) -singlepass:fail:f64.wast:1969 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.5) -singlepass:fail:f64.wast:1970 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.5) -singlepass:fail:f64.wast:1971 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-1.0) -singlepass:fail:f64.wast:1972 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-1.0) -singlepass:fail:f64.wast:1973 # "AssertReturnCanonicalNan" - value is not canonical nan F64(1.0) -singlepass:fail:f64.wast:1974 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(1.0) -singlepass:fail:f64.wast:1975 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-1.0) -singlepass:fail:f64.wast:1976 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-1.0) -singlepass:fail:f64.wast:1977 # "AssertReturnCanonicalNan" - value is not canonical nan F64(1.0) -singlepass:fail:f64.wast:1978 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(1.0) -singlepass:fail:f64.wast:1979 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-6.283185307179586) -singlepass:fail:f64.wast:1980 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-6.283185307179586) -singlepass:fail:f64.wast:1981 # "AssertReturnCanonicalNan" - value is not canonical nan F64(6.283185307179586) -singlepass:fail:f64.wast:1982 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(6.283185307179586) -singlepass:fail:f64.wast:1983 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-6.283185307179586) -singlepass:fail:f64.wast:1984 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-6.283185307179586) -singlepass:fail:f64.wast:1985 # "AssertReturnCanonicalNan" - value is not canonical nan F64(6.283185307179586) -singlepass:fail:f64.wast:1986 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(6.283185307179586) -singlepass:fail:f64.wast:1987 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1988 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1989 # "AssertReturnCanonicalNan" - value is not canonical nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1990 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1991 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1992 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1993 # "AssertReturnCanonicalNan" - value is not canonical nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1994 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1995 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-inf) -singlepass:fail:f64.wast:1996 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-inf) -singlepass:fail:f64.wast:1997 # "AssertReturnCanonicalNan" - value is not canonical nan F64(inf) -singlepass:fail:f64.wast:1998 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(inf) -singlepass:fail:f64.wast:1999 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-inf) -singlepass:fail:f64.wast:2000 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-inf) -singlepass:fail:f64.wast:2001 # "AssertReturnCanonicalNan" - value is not canonical nan F64(inf) -singlepass:fail:f64.wast:2002 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(inf) -singlepass:fail:f64.wast:2005 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2006 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2009 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2010 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2013 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2014 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2017 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2018 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2021 # AssertReturn - result F64(9223372036854775808) ("0x8000000000000000") does not match expected F64(0) ("0x0") -singlepass:fail:f64.wast:2052 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2054 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2056 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2058 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2092 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2094 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2096 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2098 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2132 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2134 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2136 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2138 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2172 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2174 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2176 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2178 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2212 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2214 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2216 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2218 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2252 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2254 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2256 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2258 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2292 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2294 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2296 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2298 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2332 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2334 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2336 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2338 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2339 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.0) -singlepass:fail:f64.wast:2340 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.0) -singlepass:fail:f64.wast:2341 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.0) -singlepass:fail:f64.wast:2342 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.0) -singlepass:fail:f64.wast:2343 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.0) -singlepass:fail:f64.wast:2344 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.0) -singlepass:fail:f64.wast:2345 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.0) -singlepass:fail:f64.wast:2346 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.0) -singlepass:fail:f64.wast:2347 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2348 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2349 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2350 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2351 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2352 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2353 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2354 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2355 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2356 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2357 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2358 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2359 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2360 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2361 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2362 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2363 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.5) -singlepass:fail:f64.wast:2364 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.5) -singlepass:fail:f64.wast:2365 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.5) -singlepass:fail:f64.wast:2366 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.5) -singlepass:fail:f64.wast:2367 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.5) -singlepass:fail:f64.wast:2368 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.5) -singlepass:fail:f64.wast:2369 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.5) -singlepass:fail:f64.wast:2370 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.5) -singlepass:fail:f64.wast:2371 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-1.0) -singlepass:fail:f64.wast:2372 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-1.0) -singlepass:fail:f64.wast:2373 # "AssertReturnCanonicalNan" - value is not canonical nan F64(1.0) -singlepass:fail:f64.wast:2374 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(1.0) -singlepass:fail:f64.wast:2375 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-1.0) -singlepass:fail:f64.wast:2376 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-1.0) -singlepass:fail:f64.wast:2377 # "AssertReturnCanonicalNan" - value is not canonical nan F64(1.0) -singlepass:fail:f64.wast:2378 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(1.0) -singlepass:fail:f64.wast:2379 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-6.283185307179586) -singlepass:fail:f64.wast:2380 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-6.283185307179586) -singlepass:fail:f64.wast:2381 # "AssertReturnCanonicalNan" - value is not canonical nan F64(6.283185307179586) -singlepass:fail:f64.wast:2382 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(6.283185307179586) -singlepass:fail:f64.wast:2383 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-6.283185307179586) -singlepass:fail:f64.wast:2384 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-6.283185307179586) -singlepass:fail:f64.wast:2385 # "AssertReturnCanonicalNan" - value is not canonical nan F64(6.283185307179586) -singlepass:fail:f64.wast:2386 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(6.283185307179586) -singlepass:fail:f64.wast:2387 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2388 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2389 # "AssertReturnCanonicalNan" - value is not canonical nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2390 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2391 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2392 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2393 # "AssertReturnCanonicalNan" - value is not canonical nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2394 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2395 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-inf) -singlepass:fail:f64.wast:2396 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-inf) -singlepass:fail:f64.wast:2397 # "AssertReturnCanonicalNan" - value is not canonical nan F64(inf) -singlepass:fail:f64.wast:2398 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(inf) -singlepass:fail:f64.wast:2399 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-inf) -singlepass:fail:f64.wast:2400 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-inf) -singlepass:fail:f64.wast:2401 # "AssertReturnCanonicalNan" - value is not canonical nan F64(inf) -singlepass:fail:f64.wast:2402 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(inf) -singlepass:fail:f64.wast:2405 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2406 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2409 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2410 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2413 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2414 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2417 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2418 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) singlepass:fail:func_ptrs.wast:78 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:func_ptrs.wast:79 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:func_ptrs.wast:80 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1467,15 +481,6 @@ singlepass:fail:i32.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i32.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:i32.wast:242 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") -singlepass:fail:i32.wast:243 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") -singlepass:fail:i32.wast:244 # AssertReturn - result I32(15) ("0xf") does not match expected I32(16) ("0x10") -singlepass:fail:i32.wast:245 # AssertReturn - result I32(7) ("0x7") does not match expected I32(24) ("0x18") -singlepass:fail:i32.wast:246 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") -singlepass:fail:i32.wast:247 # AssertReturn - result I32(0) ("0x0") does not match expected I32(31) ("0x1f") -singlepass:fail:i32.wast:248 # AssertReturn - result I32(1) ("0x1") does not match expected I32(30) ("0x1e") -singlepass:fail:i32.wast:249 # AssertReturn - result I32(30) ("0x1e") does not match expected I32(1) ("0x1") -singlepass:fail:i32.wast:252 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") singlepass:fail:i64.wast:62 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:63 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:64 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1485,15 +490,6 @@ singlepass:fail:i64.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i64.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:i64.wast:242 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") -singlepass:fail:i64.wast:243 # AssertReturn - result I64(0) ("0x0") does not match expected I64(64) ("0x40") -singlepass:fail:i64.wast:244 # AssertReturn - result I64(15) ("0xf") does not match expected I64(48) ("0x30") -singlepass:fail:i64.wast:245 # AssertReturn - result I64(7) ("0x7") does not match expected I64(56) ("0x38") -singlepass:fail:i64.wast:246 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") -singlepass:fail:i64.wast:247 # AssertReturn - result I64(0) ("0x0") does not match expected I64(63) ("0x3f") -singlepass:fail:i64.wast:248 # AssertReturn - result I64(1) ("0x1") does not match expected I64(62) ("0x3e") -singlepass:fail:i64.wast:249 # AssertReturn - result I64(62) ("0x3e") does not match expected I64(1) ("0x1") -singlepass:fail:i64.wast:252 # AssertReturn - result I64(0) ("0x0") does not match expected I64(64) ("0x40") singlepass:fail:if.wast:440 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:283 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:286 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1540,9 +536,7 @@ singlepass:fail:linking.wast:190 # AssertTrap - expected trap, got Runtime:Error singlepass:fail:linking.wast:225 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:linking.wast:236 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:linking.wast:248 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:387 # AssertReturn - result I32(0) ("0x0") does not match expected I32(104) ("0x68") singlepass:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: unknown error -singlepass:fail:load.wast:201 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") singlepass:fail:memory_grow.wast:15 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_grow.wast:16 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_grow.wast:17 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1550,7 +544,6 @@ singlepass:fail:memory_grow.wast:18 # AssertTrap - expected trap, got Runtime:Er singlepass:fail:memory_grow.wast:24 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_grow.wast:25 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_grow.wast:286 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:memory_grow.wast:299 # AssertReturn - result I32(0) ("0x0") does not match expected I32(31) ("0x1f") singlepass:fail:memory_trap.wast:23 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_trap.wast:24 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_trap.wast:25 # AssertTrap - expected trap, got Runtime:Error unknown error diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 62bfc7d53..19114ff67 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -445,8 +445,9 @@ mod tests { "AssertReturnCanonicalNan" ), message: format!( - "value is not canonical nan {:?}", - v + "value is not canonical nan {:?} ({:?})", + v, + value_to_hex(v.clone()), ), }, &test_key, @@ -512,8 +513,9 @@ mod tests { "AssertReturnArithmeticNan" ), message: format!( - "value is not arithmetic nan {:?}", - v + "value is not arithmetic nan {:?} ({:?})", + v, + value_to_hex(v.clone()), ), }, &test_key, @@ -718,10 +720,44 @@ mod tests { } } } - CommandKind::AssertUninstantiable { - module: _, - message: _, - } => println!("AssertUninstantiable not yet implmented "), + CommandKind::AssertUninstantiable { module, message: _ } => { + let spectest_import_object = get_spectest_import_object(®istered_modules); + let config = CompilerConfig { + features: Features { + simd: true, + threads: true, + }, + ..Default::default() + }; + let module = wasmer_runtime_core::compile_with_config( + &module.into_vec(), + &get_compiler(), + config, + ) + .expect("WASM can't be compiled"); + let result = panic::catch_unwind(AssertUnwindSafe(|| { + module + .instantiate(&spectest_import_object) + .expect("WASM can't be instantiated"); + })); + match result { + Err(_) => test_report.count_passed(), + Ok(_) => { + test_report.add_failure( + SpecFailure { + file: filename.to_string(), + line: line, + kind: format!("{}", "AssertUninstantiable"), + message: format!( + "instantiate successful, expected uninstantiable" + ), + }, + &test_key, + excludes, + ); + } + }; + } CommandKind::AssertExhaustion { action, message: _ } => { match action { Action::Invoke { @@ -945,6 +981,16 @@ mod tests { } } + fn value_to_hex(val: wasmer_runtime_core::types::Value) -> String { + match val { + wasmer_runtime_core::types::Value::I32(x) => format!("{:#x}", x), + wasmer_runtime_core::types::Value::I64(x) => format!("{:#x}", x), + wasmer_runtime_core::types::Value::F32(x) => format!("{:#x}", x.to_bits()), + wasmer_runtime_core::types::Value::F64(x) => format!("{:#x}", x.to_bits()), + wasmer_runtime_core::types::Value::V128(x) => format!("{:#x}", x), + } + } + #[derive(Debug, Clone, Eq, PartialEq)] pub enum SpectestValue { I32(i32), diff --git a/lib/wasi-tests/Cargo.toml b/lib/wasi-tests/Cargo.toml index 580f0303d..96626f6cf 100644 --- a/lib/wasi-tests/Cargo.toml +++ b/lib/wasi-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi-tests" -version = "0.8.0" +version = "0.9.0" description = "Tests for our WASI implementation" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,20 +9,20 @@ publish = false build = "build/mod.rs" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmer-runtime = { path = "../runtime", version = "0.8.0" } -wasmer-wasi = { path = "../wasi", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-runtime = { path = "../runtime", version = "0.9.0" } +wasmer-wasi = { path = "../wasi", version = "0.9.0" } # hack to get tests to work -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.8.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9.0", optional = true } [build-dependencies] glob = "0.3" [dev-dependencies] -wasmer-clif-backend = { path = "../clif-backend", version = "0.8.0" } -wasmer-dev-utils = { path = "../dev-utils", version = "0.8.0"} +wasmer-clif-backend = { path = "../clif-backend", version = "0.9.0" } +wasmer-dev-utils = { path = "../dev-utils", version = "0.9.0"} [features] clif = [] diff --git a/lib/wasi-tests/tests/wasitests/fd_close.rs b/lib/wasi-tests/tests/wasitests/fd_close.rs new file mode 100644 index 000000000..8bff35789 --- /dev/null +++ b/lib/wasi-tests/tests/wasitests/fd_close.rs @@ -0,0 +1,18 @@ +// !!! THIS IS A GENERATED FILE !!! +// ANY MANUAL EDITS MAY BE OVERWRITTEN AT ANY TIME +// Files autogenerated with cargo build (build/wasitests.rs). + +#[test] +fn test_fd_close() { + assert_wasi_output!( + "../../wasitests/fd_close.wasm", + "fd_close", + vec![], + vec![( + ".".to_string(), + ::std::path::PathBuf::from("wasitests/test_fs/hamlet") + ),], + vec![], + "../../wasitests/fd_close.out" + ); +} diff --git a/lib/wasi-tests/tests/wasitests/mod.rs b/lib/wasi-tests/tests/wasitests/mod.rs index e469511fd..75a91d6f0 100644 --- a/lib/wasi-tests/tests/wasitests/mod.rs +++ b/lib/wasi-tests/tests/wasitests/mod.rs @@ -9,6 +9,7 @@ mod close_preopen_fd; mod create_dir; mod envvar; mod fd_allocate; +mod fd_close; mod fd_pread; mod fd_read; mod fd_sync; diff --git a/lib/wasi-tests/wasitests/fd_close.out b/lib/wasi-tests/wasitests/fd_close.out new file mode 100644 index 000000000..53c9c2727 --- /dev/null +++ b/lib/wasi-tests/wasitests/fd_close.out @@ -0,0 +1,3 @@ +Successfully closed file! +Successfully closed stderr! +Successfully closed stdin! diff --git a/lib/wasi-tests/wasitests/fd_close.rs b/lib/wasi-tests/wasitests/fd_close.rs new file mode 100644 index 000000000..e5cdaafd9 --- /dev/null +++ b/lib/wasi-tests/wasitests/fd_close.rs @@ -0,0 +1,63 @@ +// Args: +// mapdir: .:wasitests/test_fs/hamlet + +use std::fs; +#[cfg(target_os = "wasi")] +use std::os::wasi::prelude::AsRawFd; +use std::path::PathBuf; + +#[cfg(target_os = "wasi")] +#[link(wasm_import_module = "wasi_unstable")] +extern "C" { + fn fd_close(fd: u32) -> u16; +} + +fn main() { + #[cfg(not(target_os = "wasi"))] + let mut base = PathBuf::from("wasitests/test_fs/hamlet"); + #[cfg(target_os = "wasi")] + let mut base = PathBuf::from("."); + + base.push("act3/scene3.txt"); + let file = fs::File::open(&base).expect("could not open file"); + + #[cfg(target_os = "wasi")] + { + let file_fd = file.as_raw_fd(); + let stdout_fd = std::io::stdout().as_raw_fd(); + let stderr_fd = std::io::stderr().as_raw_fd(); + let stdin_fd = std::io::stdin().as_raw_fd(); + + let result = unsafe { fd_close(file_fd) }; + if result == 0 { + println!("Successfully closed file!") + } else { + println!("Could not close file"); + } + + let result = unsafe { fd_close(stderr_fd) }; + if result == 0 { + println!("Successfully closed stderr!") + } else { + println!("Could not close stderr"); + } + let result = unsafe { fd_close(stdin_fd) }; + if result == 0 { + println!("Successfully closed stdin!") + } else { + println!("Could not close stdin"); + } + let result = unsafe { fd_close(stdout_fd) }; + if result == 0 { + println!("Successfully closed stdout!") + } else { + println!("Could not close stdout"); + } + } + #[cfg(not(target_os = "wasi"))] + { + println!("Successfully closed file!"); + println!("Successfully closed stderr!"); + println!("Successfully closed stdin!"); + } +} diff --git a/lib/wasi-tests/wasitests/fd_close.wasm b/lib/wasi-tests/wasitests/fd_close.wasm new file mode 100755 index 000000000..5ace52062 Binary files /dev/null and b/lib/wasi-tests/wasitests/fd_close.wasm differ diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 067894dde..e73b57ea4 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime WASI implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -13,11 +13,11 @@ byteorder = "1.3" generational-arena = { version = "0.2", features = ["serde"] } libc = "0.2.60" log = "0.4" -rand = "0.7" +getrandom = "0.1" time = "0.1" typetag = "0.1" serde = { version = "1", features = ["derive"] } -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } [target.'cfg(windows)'.dependencies] winapi = "0.3" diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 39fd38378..04b206c30 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -37,6 +37,19 @@ use wasmer_runtime_core::{debug, vm::Ctx}; pub const VIRTUAL_ROOT_FD: __wasi_fd_t = 3; /// all the rights enabled pub const ALL_RIGHTS: __wasi_rights_t = 0x1FFFFFFF; +const STDIN_DEFAULT_RIGHTS: __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC + | __WASI_RIGHT_FD_READ + | __WASI_RIGHT_FD_SYNC + | __WASI_RIGHT_FD_ADVISE + | __WASI_RIGHT_FD_FILESTAT_GET + | __WASI_RIGHT_POLL_FD_READWRITE; +const STDOUT_DEFAULT_RIGHTS: __wasi_rights_t = __WASI_RIGHT_FD_DATASYNC + | __WASI_RIGHT_FD_WRITE + | __WASI_RIGHT_FD_SYNC + | __WASI_RIGHT_FD_ADVISE + | __WASI_RIGHT_FD_FILESTAT_GET + | __WASI_RIGHT_POLL_FD_READWRITE; +const STDERR_DEFAULT_RIGHTS: __wasi_rights_t = STDOUT_DEFAULT_RIGHTS; /// Get WasiState from a Ctx /// This function is unsafe because it must be called on a WASI Ctx @@ -109,6 +122,7 @@ pub struct Fd { pub rights_inheriting: __wasi_rights_t, pub flags: __wasi_fdflags_t, pub offset: u64, + /// Used when reopening the file on the host system pub open_flags: u16, pub inode: Inode, } @@ -134,10 +148,6 @@ pub struct WasiFs { inode_counter: Cell, /// for fds still open after the file has been deleted pub orphan_fds: HashMap, - - pub stdout: Box, - pub stderr: Box, - pub stdin: Box, } impl WasiFs { @@ -155,11 +165,11 @@ impl WasiFs { next_fd: Cell::new(3), inode_counter: Cell::new(1024), orphan_fds: HashMap::new(), - - stdin: Box::new(Stdin), - stdout: Box::new(Stdout), - stderr: Box::new(Stderr), }; + wasi_fs.create_stdin(); + wasi_fs.create_stdout(); + wasi_fs.create_stderr(); + // create virtual root let root_inode = { let all_rights = 0x1FFFFFFF; @@ -291,6 +301,67 @@ impl WasiFs { Ok(wasi_fs) } + /// Get the `WasiFile` object at stdout + pub fn stdout(&self) -> Result<&Option>, WasiFsError> { + self.std_dev_get(__WASI_STDOUT_FILENO) + } + /// Get the `WasiFile` object at stdout mutably + pub fn stdout_mut(&mut self) -> Result<&mut Option>, WasiFsError> { + self.std_dev_get_mut(__WASI_STDOUT_FILENO) + } + + /// Get the `WasiFile` object at stderr + pub fn stderr(&self) -> Result<&Option>, WasiFsError> { + self.std_dev_get(__WASI_STDERR_FILENO) + } + /// Get the `WasiFile` object at stderr mutably + pub fn stderr_mut(&mut self) -> Result<&mut Option>, WasiFsError> { + self.std_dev_get_mut(__WASI_STDERR_FILENO) + } + + /// Get the `WasiFile` object at stdin + pub fn stdin(&self) -> Result<&Option>, WasiFsError> { + self.std_dev_get(__WASI_STDIN_FILENO) + } + /// Get the `WasiFile` object at stdin mutably + pub fn stdin_mut(&mut self) -> Result<&mut Option>, WasiFsError> { + self.std_dev_get_mut(__WASI_STDIN_FILENO) + } + + /// Internal helper function to get a standard device handle. + /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. + fn std_dev_get(&self, fd: __wasi_fd_t) -> Result<&Option>, WasiFsError> { + if let Some(fd) = self.fd_map.get(&fd) { + if let Kind::File { ref handle, .. } = self.inodes[fd.inode].kind { + Ok(handle) + } else { + // Our public API should ensure that this is not possible + unreachable!("Non-file found in standard device location") + } + } else { + // this should only trigger if we made a mistake in this crate + Err(WasiFsError::NoDevice) + } + } + /// Internal helper function to mutably get a standard device handle. + /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. + fn std_dev_get_mut( + &mut self, + fd: __wasi_fd_t, + ) -> Result<&mut Option>, WasiFsError> { + if let Some(fd) = self.fd_map.get_mut(&fd) { + if let Kind::File { ref mut handle, .. } = self.inodes[fd.inode].kind { + Ok(handle) + } else { + // Our public API should ensure that this is not possible + unreachable!("Non-file found in standard device location") + } + } else { + // this should only trigger if we made a mistake in this crate + Err(WasiFsError::NoDevice) + } + } + fn get_next_inode_index(&mut self) -> u64 { let next = self.inode_counter.get(); self.inode_counter.set(next + 1); @@ -358,21 +429,16 @@ impl WasiFs { fd: __wasi_fd_t, file: Box, ) -> Result>, WasiFsError> { + let mut ret = Some(file); match fd { __WASI_STDIN_FILENO => { - let mut ret = file; - std::mem::swap(&mut self.stdin, &mut ret); - Ok(Some(ret)) + std::mem::swap(self.stdin_mut()?, &mut ret); } __WASI_STDOUT_FILENO => { - let mut ret = file; - std::mem::swap(&mut self.stdout, &mut ret); - Ok(Some(ret)) + std::mem::swap(self.stdout_mut()?, &mut ret); } __WASI_STDERR_FILENO => { - let mut ret = file; - std::mem::swap(&mut self.stderr, &mut ret); - Ok(Some(ret)) + std::mem::swap(self.stderr_mut()?, &mut ret); } _ => { let base_fd = self.get_fd(fd).map_err(WasiFsError::from_wasi_err)?; @@ -380,14 +446,14 @@ impl WasiFs { match &mut self.inodes[base_inode].kind { Kind::File { ref mut handle, .. } => { - let mut ret = Some(file); std::mem::swap(handle, &mut ret); - Ok(ret) } _ => return Err(WasiFsError::NotAFile), } } } + + Ok(ret) } /// refresh size from filesystem @@ -733,6 +799,17 @@ impl WasiFs { } pub fn fdstat(&self, fd: __wasi_fd_t) -> Result<__wasi_fdstat_t, __wasi_errno_t> { + match fd { + __WASI_STDOUT_FILENO => { + return Ok(__wasi_fdstat_t { + fs_filetype: __WASI_FILETYPE_CHARACTER_DEVICE, + fs_flags: 0, + fs_rights_base: ALL_RIGHTS, + fs_rights_inheriting: ALL_RIGHTS, + }) + } + _ => (), + } let fd = self.get_fd(fd)?; debug!("fdstat: {:?}", fd); @@ -773,8 +850,18 @@ impl WasiFs { pub fn flush(&mut self, fd: __wasi_fd_t) -> Result<(), __wasi_errno_t> { match fd { __WASI_STDIN_FILENO => (), - __WASI_STDOUT_FILENO => self.stdout.flush().map_err(|_| __WASI_EIO)?, - __WASI_STDERR_FILENO => self.stderr.flush().map_err(|_| __WASI_EIO)?, + __WASI_STDOUT_FILENO => self + .stdout_mut() + .map_err(WasiFsError::into_wasi_err)? + .as_mut() + .and_then(|f| f.flush().ok()) + .ok_or(__WASI_EIO)?, + __WASI_STDERR_FILENO => self + .stderr_mut() + .map_err(WasiFsError::into_wasi_err)? + .as_mut() + .and_then(|f| f.flush().ok()) + .ok_or(__WASI_EIO)?, _ => { let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?; if fd.rights & __WASI_RIGHT_FD_DATASYNC == 0 { @@ -793,7 +880,7 @@ impl WasiFs { } // TODO: verify this behavior Kind::Dir { .. } => return Err(__WASI_EISDIR), - Kind::Symlink { .. } => unimplemented!(), + Kind::Symlink { .. } => unimplemented!("WasiFs::flush Kind::Symlink"), Kind::Buffer { .. } => (), _ => return Err(__WASI_EIO), } @@ -881,13 +968,78 @@ impl WasiFs { }; self.inodes.insert(InodeVal { - stat: stat, + stat, is_preopened: true, name: "/".to_string(), kind: root_kind, }) } + fn create_stdout(&mut self) { + self.create_std_dev_inner( + Box::new(Stdout), + "stdout", + __WASI_STDOUT_FILENO, + STDOUT_DEFAULT_RIGHTS, + __WASI_FDFLAG_APPEND, + ); + } + fn create_stdin(&mut self) { + self.create_std_dev_inner( + Box::new(Stdin), + "stdin", + __WASI_STDIN_FILENO, + STDIN_DEFAULT_RIGHTS, + 0, + ); + } + fn create_stderr(&mut self) { + self.create_std_dev_inner( + Box::new(Stderr), + "stderr", + __WASI_STDERR_FILENO, + STDERR_DEFAULT_RIGHTS, + __WASI_FDFLAG_APPEND, + ); + } + + fn create_std_dev_inner( + &mut self, + handle: Box, + name: &'static str, + raw_fd: __wasi_fd_t, + rights: __wasi_rights_t, + fd_flags: __wasi_fdflags_t, + ) { + let stat = __wasi_filestat_t { + st_filetype: __WASI_FILETYPE_CHARACTER_DEVICE, + st_ino: self.get_next_inode_index(), + ..__wasi_filestat_t::default() + }; + let kind = Kind::File { + handle: Some(handle), + path: "".into(), + }; + let inode = self.inodes.insert(InodeVal { + stat, + is_preopened: true, + name: name.to_string(), + kind, + }); + self.fd_map.insert( + raw_fd, + Fd { + rights, + rights_inheriting: 0, + flags: fd_flags, + // since we're not calling open on this, we don't need open flags + open_flags: 0, + offset: 0, + inode, + }, + ); + } + pub fn get_stat_for_kind(&self, kind: &Kind) -> Option<__wasi_filestat_t> { let md = match kind { Kind::File { handle, path } => match handle { diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 2f97a5fe3..5eb55c670 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -49,6 +49,8 @@ pub enum WasiFsError { NotConnected, /// The requested file or directory could not be found EntityNotFound, + /// The requested device couldn't be accessed + NoDevice, /// Caller was not allowed to perform this operation PermissionDenied, /// The operation did not complete within the given amount of time @@ -80,6 +82,7 @@ impl WasiFsError { __WASI_EINTR => WasiFsError::Interrupted, __WASI_EINVAL => WasiFsError::InvalidInput, __WASI_ENOTCONN => WasiFsError::NotConnected, + __WASI_ENODEV => WasiFsError::NoDevice, __WASI_ENOENT => WasiFsError::EntityNotFound, __WASI_EPERM => WasiFsError::PermissionDenied, __WASI_ETIMEDOUT => WasiFsError::TimedOut, @@ -105,6 +108,7 @@ impl WasiFsError { WasiFsError::InvalidFd => __WASI_EBADF, WasiFsError::InvalidInput => __WASI_EINVAL, WasiFsError::IOError => __WASI_EIO, + WasiFsError::NoDevice => __WASI_ENODEV, WasiFsError::NotAFile => __WASI_EINVAL, WasiFsError::NotConnected => __WASI_ENOTCONN, WasiFsError::EntityNotFound => __WASI_ENOENT, diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 90dbfd458..585469035 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -15,7 +15,6 @@ use crate::{ }, ExitCode, }; -use rand::{thread_rng, Rng}; use std::borrow::Borrow; use std::cell::Cell; use std::convert::{Infallible, TryInto}; @@ -374,6 +373,7 @@ pub fn fd_allocate( /// If `fd` is invalid or not open pub fn fd_close(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_close"); + debug!("=> fd={}", fd); let state = get_wasi_state(ctx); let fd_entry = wasi_try!(state.fs.get_fd(fd)).clone(); @@ -662,7 +662,15 @@ pub fn fd_pread( let state = get_wasi_state(ctx); let bytes_read = match fd { - __WASI_STDIN_FILENO => wasi_try!(read_bytes(&mut state.fs.stdin, memory, iov_cells)), + __WASI_STDIN_FILENO => { + if let Some(ref mut stdin) = + wasi_try!(state.fs.stdin_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(read_bytes(stdin, memory, iov_cells)) + } else { + return __WASI_EBADF; + } + } __WASI_STDOUT_FILENO => return __WASI_EINVAL, __WASI_STDERR_FILENO => return __WASI_EINVAL, _ => { @@ -802,8 +810,24 @@ pub fn fd_pwrite( let bytes_written = match fd { __WASI_STDIN_FILENO => return __WASI_EINVAL, - __WASI_STDOUT_FILENO => wasi_try!(write_bytes(&mut state.fs.stdout, memory, iovs_arr_cell)), - __WASI_STDERR_FILENO => wasi_try!(write_bytes(&mut state.fs.stderr, memory, iovs_arr_cell)), + __WASI_STDOUT_FILENO => { + if let Some(ref mut stdout) = + wasi_try!(state.fs.stdout_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(write_bytes(stdout, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } + __WASI_STDERR_FILENO => { + if let Some(ref mut stderr) = + wasi_try!(state.fs.stderr_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(write_bytes(stderr, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } _ => { let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -872,7 +896,15 @@ pub fn fd_read( let state = get_wasi_state(ctx); let bytes_read = match fd { - __WASI_STDIN_FILENO => wasi_try!(read_bytes(&mut state.fs.stdin, memory, iovs_arr_cell)), + __WASI_STDIN_FILENO => { + if let Some(ref mut stdin) = + wasi_try!(state.fs.stdin_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(read_bytes(stdin, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => return __WASI_EINVAL, _ => { let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -1211,8 +1243,24 @@ pub fn fd_write( let bytes_written = match fd { __WASI_STDIN_FILENO => return __WASI_EINVAL, - __WASI_STDOUT_FILENO => wasi_try!(write_bytes(&mut state.fs.stdout, memory, iovs_arr_cell)), - __WASI_STDERR_FILENO => wasi_try!(write_bytes(&mut state.fs.stderr, memory, iovs_arr_cell)), + __WASI_STDOUT_FILENO => { + if let Some(ref mut stdout) = + wasi_try!(state.fs.stdout_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(write_bytes(stdout, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } + __WASI_STDERR_FILENO => { + if let Some(ref mut stderr) = + wasi_try!(state.fs.stderr_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(write_bytes(stderr, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } _ => { let state = get_wasi_state(ctx); let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -2292,9 +2340,21 @@ pub fn poll_oneoff( if let Some(fd) = fd { let wasi_file_ref: &dyn WasiFile = match fd { - __WASI_STDERR_FILENO => state.fs.stderr.as_ref(), - __WASI_STDIN_FILENO => state.fs.stdin.as_ref(), - __WASI_STDOUT_FILENO => state.fs.stdout.as_ref(), + __WASI_STDERR_FILENO => wasi_try!( + wasi_try!(state.fs.stderr().map_err(WasiFsError::into_wasi_err)).as_ref(), + __WASI_EBADF + ) + .as_ref(), + __WASI_STDIN_FILENO => wasi_try!( + wasi_try!(state.fs.stdin().map_err(WasiFsError::into_wasi_err)).as_ref(), + __WASI_EBADF + ) + .as_ref(), + __WASI_STDOUT_FILENO => wasi_try!( + wasi_try!(state.fs.stdout().map_err(WasiFsError::into_wasi_err)).as_ref(), + __WASI_EBADF + ) + .as_ref(), _ => { let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; @@ -2392,17 +2452,18 @@ pub fn proc_raise(ctx: &mut Ctx, sig: __wasi_signal_t) -> __wasi_errno_t { /// The number of bytes that will be written pub fn random_get(ctx: &mut Ctx, buf: WasmPtr, buf_len: u32) -> __wasi_errno_t { debug!("wasi::random_get buf_len: {}", buf_len); - let mut rng = thread_rng(); let memory = ctx.memory(0); let buf = wasi_try!(buf.deref(memory, 0, buf_len)); - unsafe { + let res = unsafe { let u8_buffer = &mut *(buf as *const [_] as *mut [_] as *mut [u8]); - thread_rng().fill(u8_buffer); + getrandom::getrandom(u8_buffer) + }; + match res { + Ok(()) => __WASI_ESUCCESS, + Err(_) => __WASI_EIO, } - - __WASI_ESUCCESS } /// ### `sched_yield()` diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index d2aaa0554..d0082ef69 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -8,12 +8,12 @@ use std::mem; use wasmer_runtime_core::types::ValueType; pub type __wasi_advice_t = u8; -pub const __WASI_ADVICE_DONTNEED: u8 = 0; -pub const __WASI_ADVICE_NOREUSE: u8 = 1; -pub const __WASI_ADVICE_NORMAL: u8 = 2; -pub const __WASI_ADVICE_RANDOM: u8 = 3; -pub const __WASI_ADVICE_SEQUENTIAL: u8 = 4; -pub const __WASI_ADVICE_WILLNEED: u8 = 5; +pub const __WASI_ADVICE_NORMAL: u8 = 0; +pub const __WASI_ADVICE_SEQUENTIAL: u8 = 1; +pub const __WASI_ADVICE_RANDOM: u8 = 2; +pub const __WASI_ADVICE_WILLNEED: u8 = 3; +pub const __WASI_ADVICE_DONTNEED: u8 = 4; +pub const __WASI_ADVICE_NOREUSE: u8 = 5; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(C)] diff --git a/lib/win-exception-handler/Cargo.toml b/lib/win-exception-handler/Cargo.toml index 12e5f6c0b..b3281c511 100644 --- a/lib/win-exception-handler/Cargo.toml +++ b/lib/win-exception-handler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-win-exception-handler" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime exception handling for Windows" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -8,11 +8,9 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" [target.'cfg(windows)'.dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } winapi = { version = "0.3.8", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] } libc = "0.2.60" [build-dependencies] cmake = "0.1" -bindgen = "0.51" -regex = "1.2" diff --git a/lib/win-exception-handler/src/exception_handling.rs b/lib/win-exception-handler/src/exception_handling.rs index c448392b0..712214c8b 100644 --- a/lib/win-exception-handler/src/exception_handling.rs +++ b/lib/win-exception-handler/src/exception_handling.rs @@ -1,7 +1,9 @@ use std::ptr::NonNull; -use wasmer_runtime_core::vm::{Ctx, Func}; +use wasmer_runtime_core::{ + typed_func::Trampoline, + vm::{Ctx, Func}, +}; -type Trampoline = unsafe extern "C" fn(*mut Ctx, NonNull, *const u64, *mut u64); type CallProtectedResult = Result<(), CallProtectedData>; #[repr(C)] diff --git a/scripts/update_version_numbers.sh b/scripts/update_version_numbers.sh index 21b28a916..d93bdefb4 100755 --- a/scripts/update_version_numbers.sh +++ b/scripts/update_version_numbers.sh @@ -1,5 +1,5 @@ -PREVIOUS_VERSION='0.7.0' -NEXT_VERSION='0.8.0' +PREVIOUS_VERSION='0.8.0' +NEXT_VERSION='0.9.0' # quick hack fd Cargo.toml --exec sed -i '' "s/version = \"$PREVIOUS_VERSION\"/version = \"$NEXT_VERSION\"/" diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 3906ce890..58cead255 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -23,7 +23,7 @@ use structopt::StructOpt; use wasmer::*; use wasmer_clif_backend::CraneliftCompiler; #[cfg(feature = "backend-llvm")] -use wasmer_llvm_backend::LLVMCompiler; +use wasmer_llvm_backend::{LLVMCompiler, LLVMOptions}; use wasmer_runtime::{ cache::{Cache as BaseCache, FileSystemCache, WasmHash}, Func, Value, VERSION, @@ -109,7 +109,7 @@ pub struct LLVMCLIOptions { post_opt_ir: Option, /// Emit LLVM generated native code object file. - #[structopt(long = "backend-llvm-object-file", parse(from_os_str))] + #[structopt(long = "llvm-object-file", parse(from_os_str))] obj_file: Option, } @@ -177,8 +177,8 @@ struct Run { /// Whether or not state tracking should be disabled during compilation. /// State tracking is necessary for tier switching and backtracing. - #[structopt(long = "no-track-state")] - no_track_state: bool, + #[structopt(long = "track-state")] + track_state: bool, /// The command name is a string that will override the first argument passed /// to the wasm program. This is used in wapm to provide nicer output in @@ -405,7 +405,21 @@ fn execute_wasm(options: &Run) -> Result<(), String> { None => return Err("the requested backend is not enabled".into()), }; - let track_state = !options.no_track_state; + #[cfg(feature = "backend-llvm")] + { + if options.backend == Backend::LLVM { + let options = options.backend_llvm_options.clone(); + unsafe { + wasmer_llvm_backend::GLOBAL_OPTIONS = LLVMOptions { + pre_opt_ir: options.pre_opt_ir, + post_opt_ir: options.post_opt_ir, + obj_file: options.obj_file, + } + } + } + } + + let track_state = options.track_state; #[cfg(feature = "loader-kernel")] let is_kernel_loader = if let Some(LoaderName::Kernel) = options.loader { diff --git a/src/installer/wasmer.iss b/src/installer/wasmer.iss index a5a24951a..cce60f984 100644 --- a/src/installer/wasmer.iss +++ b/src/installer/wasmer.iss @@ -1,6 +1,6 @@ [Setup] AppName=Wasmer -AppVersion=0.8.0 +AppVersion=0.9.0 DefaultDirName={pf}\Wasmer DefaultGroupName=Wasmer Compression=lzma2