mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Implement many wasm instructions
This commit is contained in:
parent
aa90a33501
commit
327e3a4a1a
169
Cargo.lock
generated
169
Cargo.lock
generated
@ -1,3 +1,11 @@
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
@ -28,7 +36,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.2"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -178,6 +186,20 @@ dependencies = [
|
||||
"generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "enum-methods"
|
||||
version = "0.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.4"
|
||||
@ -281,6 +303,27 @@ name = "indexmap"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "inkwell"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/TheDan64/inkwell?branch=llvm7-0#83b9188bad1e098f97e6aad8f6d45becb6d1ccdd"
|
||||
dependencies = [
|
||||
"either 1.5.0 (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/TheDan64/inkwell?branch=llvm7-0)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"llvm-sys 70.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inkwell_internal_macros"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/TheDan64/inkwell?branch=llvm7-0#83b9188bad1e098f97e6aad8f6d45becb6d1ccdd"
|
||||
dependencies = [
|
||||
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.3"
|
||||
@ -310,6 +353,29 @@ name = "libc"
|
||||
version = "0.2.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "llvm-backend"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)",
|
||||
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasmer-runtime-core 0.1.2",
|
||||
"wasmparser 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "llvm-sys"
|
||||
version = "70.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.1.5"
|
||||
@ -327,6 +393,15 @@ dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap"
|
||||
version = "0.7.0"
|
||||
@ -412,6 +487,11 @@ dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.11"
|
||||
@ -547,6 +627,26 @@ dependencies = [
|
||||
"redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
@ -625,7 +725,7 @@ name = "sha2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -669,6 +769,16 @@ dependencies = [
|
||||
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.11.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.26"
|
||||
@ -679,6 +789,14 @@ dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synom"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.10.1"
|
||||
@ -718,6 +836,14 @@ dependencies = [
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
@ -733,6 +859,11 @@ name = "typenum"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.2.1"
|
||||
@ -743,6 +874,11 @@ name = "unicode-width"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
@ -756,6 +892,11 @@ dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf8-ranges"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.1"
|
||||
@ -886,6 +1027,11 @@ name = "wasmparser"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
@ -916,11 +1062,12 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum block-buffer 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "509de513cca6d92b6aacf9c61acfe7eaa160837323a81068d690cc1f8e5740da"
|
||||
"checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d"
|
||||
"checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591"
|
||||
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
|
||||
@ -938,6 +1085,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum cranelift-native 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "474bee81d620a473bf43411a3d6f10ffbf7965141dc5e5b76d8d2151dde3285d"
|
||||
"checksum cranelift-wasm 0.26.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49723365dab9a48b354bdc24cb6d9d5719bc1d3b858ffd2ea179d0d7d885804a"
|
||||
"checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
|
||||
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
|
||||
"checksum enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7798e7da2d4cb0d6d6fc467e8d6b5bf247e9e989f786dde1732d79899c32bb10"
|
||||
"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"
|
||||
@ -952,13 +1101,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum hashbrown 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3bae29b6653b3412c2e71e9d486db9f9df5d701941d86683005efb9f2d28e3da"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
||||
"checksum inkwell 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)" = "<none>"
|
||||
"checksum inkwell_internal_macros 0.1.0 (git+https://github.com/TheDan64/inkwell?branch=llvm7-0)" = "<none>"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum libc 0.2.48 (git+https://github.com/rust-lang/libc)" = "<none>"
|
||||
"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047"
|
||||
"checksum llvm-sys 70.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60a9ee82fe0fa72ae6ef6d018b407296085863836451c7a97384f84ed7e26b9f"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8"
|
||||
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
||||
"checksum nix 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "921f61dc817b379d0834e45d5ec45beaacfae97082090a49c2cf30dcbc30206f"
|
||||
"checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b"
|
||||
@ -968,6 +1121,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
|
||||
"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
|
||||
"checksum proc-macro2 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "38fddd23d98b2144d197c0eca5705632d4fe2667d14a6be5df8934f8d74f1978"
|
||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
|
||||
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
|
||||
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
|
||||
@ -983,6 +1137,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
|
||||
"checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
@ -999,23 +1155,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum structopt 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "670ad348dc73012fcf78c71f06f9d942232cdd4c859d4b6975e27836c3efc0c3"
|
||||
"checksum structopt-derive 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ef98172b1a00b0bec738508d3726540edcbd186d50dfd326f2b1febbb3559f04"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
|
||||
"checksum target-lexicon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4af5e2227f0b887d591d3724b796a96eff04226104d872f5b3883fcd427d64b9"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
"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 typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"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 unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "74e463a508e390cc7447e70f640fbf44ad52e1bd095314ace1fdf99516d32add"
|
||||
"checksum wabt-sys 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a6265b25719e82598d104b3717375e37661d41753e2c84cde3f51050c7ed7e3c"
|
||||
"checksum wasmparser 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e666ecb4a406483a59a49f9d0c17f327e70da53a128eccddae2eadb95865c"
|
||||
"checksum wasmparser 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5e01c420bc7d36e778bd242e1167b079562ba8b34087122cc9057187026d060"
|
||||
"checksum wasmparser 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "40f426b1929bd26517fb10702e2a8e520d1845c49567aa4d244f426f10b206c1"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
|
@ -27,7 +27,7 @@ wasmer-runtime-core = { path = "lib/runtime-core" }
|
||||
wasmer-emscripten = { path = "lib/emscripten" }
|
||||
|
||||
[workspace]
|
||||
members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests"]
|
||||
members = ["lib/clif-backend", "lib/runtime", "lib/runtime-core", "lib/emscripten", "lib/spectests", "lib/llvm-backend"]
|
||||
|
||||
[build-dependencies]
|
||||
wabt = "0.7.2"
|
||||
|
@ -75,7 +75,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
let local_global_addr = match global_index.local_or_import(self.env.module) {
|
||||
let local_global_addr = match global_index.local_or_import(&self.env.module.info) {
|
||||
LocalOrImport::Local(local_global_index) => {
|
||||
let globals_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
@ -145,48 +145,49 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
let (local_memory_ptr_ptr, description) = match mem_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_memories() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let local_memory_ptr_offset =
|
||||
local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
|
||||
|
||||
(
|
||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: memories_base_addr,
|
||||
offset: (local_memory_ptr_offset as i64).into(),
|
||||
let (local_memory_ptr_ptr, description) =
|
||||
match mem_index.local_or_import(&self.env.module.info) {
|
||||
LocalOrImport::Local(local_mem_index) => {
|
||||
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_memories() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
}),
|
||||
self.env.module.info.memories[local_mem_index],
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(import_mem_index) => {
|
||||
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_memories() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
readonly: true,
|
||||
});
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let local_memory_ptr_offset =
|
||||
import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
|
||||
let local_memory_ptr_offset =
|
||||
local_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
|
||||
|
||||
(
|
||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: memories_base_addr,
|
||||
offset: (local_memory_ptr_offset as i64).into(),
|
||||
(
|
||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: memories_base_addr,
|
||||
offset: (local_memory_ptr_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
}),
|
||||
self.env.module.info.memories[local_mem_index],
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(import_mem_index) => {
|
||||
let memories_base_addr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
base: vmctx,
|
||||
offset: (vm::Ctx::offset_imported_memories() as i32).into(),
|
||||
global_type: ptr_type,
|
||||
}),
|
||||
self.env.module.info.imported_memories[import_mem_index].1,
|
||||
)
|
||||
}
|
||||
};
|
||||
readonly: true,
|
||||
});
|
||||
|
||||
let local_memory_ptr_offset =
|
||||
import_mem_index.index() * mem::size_of::<*mut vm::LocalMemory>();
|
||||
|
||||
(
|
||||
func.create_global_value(ir::GlobalValueData::IAddImm {
|
||||
base: memories_base_addr,
|
||||
offset: (local_memory_ptr_offset as i64).into(),
|
||||
global_type: ptr_type,
|
||||
}),
|
||||
self.env.module.info.imported_memories[import_mem_index].1,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let (local_memory_ptr, local_memory_base) = {
|
||||
let local_memory_ptr = func.create_global_value(ir::GlobalValueData::Load {
|
||||
@ -253,7 +254,8 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
||||
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
|
||||
let ptr_type = self.pointer_type();
|
||||
|
||||
let (table_struct_ptr_ptr, description) = match table_index.local_or_import(self.env.module)
|
||||
let (table_struct_ptr_ptr, description) = match table_index
|
||||
.local_or_import(&self.env.module.info)
|
||||
{
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
let tables_base = func.create_global_value(ir::GlobalValueData::Load {
|
||||
@ -476,7 +478,7 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
||||
) -> cranelift_wasm::WasmResult<ir::Inst> {
|
||||
let callee_index: FuncIndex = Converter(clif_callee_index).into();
|
||||
|
||||
match callee_index.local_or_import(self.env.module) {
|
||||
match callee_index.local_or_import(&self.env.module.info) {
|
||||
LocalOrImport::Local(_) => {
|
||||
// this is an internal function
|
||||
let vmctx = pos
|
||||
@ -568,18 +570,19 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
||||
|
||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||
|
||||
let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_mem_index) => (
|
||||
call_names::LOCAL_NAMESPACE,
|
||||
local_mem_index.index(),
|
||||
self.env.module.info.memories[local_mem_index],
|
||||
),
|
||||
LocalOrImport::Import(import_mem_index) => (
|
||||
call_names::IMPORT_NAMESPACE,
|
||||
import_mem_index.index(),
|
||||
self.env.module.info.imported_memories[import_mem_index].1,
|
||||
),
|
||||
};
|
||||
let (namespace, mem_index, description) =
|
||||
match mem_index.local_or_import(&self.env.module.info) {
|
||||
LocalOrImport::Local(local_mem_index) => (
|
||||
call_names::LOCAL_NAMESPACE,
|
||||
local_mem_index.index(),
|
||||
self.env.module.info.memories[local_mem_index],
|
||||
),
|
||||
LocalOrImport::Import(import_mem_index) => (
|
||||
call_names::IMPORT_NAMESPACE,
|
||||
import_mem_index.index(),
|
||||
self.env.module.info.imported_memories[import_mem_index].1,
|
||||
),
|
||||
};
|
||||
|
||||
let name_index = match description.memory_type() {
|
||||
MemoryType::Dynamic => call_names::DYNAMIC_MEM_GROW,
|
||||
@ -631,18 +634,19 @@ impl<'env, 'module, 'isa> FuncEnvironment for FuncEnv<'env, 'module, 'isa> {
|
||||
|
||||
let mem_index: MemoryIndex = Converter(clif_mem_index).into();
|
||||
|
||||
let (namespace, mem_index, description) = match mem_index.local_or_import(self.env.module) {
|
||||
LocalOrImport::Local(local_mem_index) => (
|
||||
call_names::LOCAL_NAMESPACE,
|
||||
local_mem_index.index(),
|
||||
self.env.module.info.memories[local_mem_index],
|
||||
),
|
||||
LocalOrImport::Import(import_mem_index) => (
|
||||
call_names::IMPORT_NAMESPACE,
|
||||
import_mem_index.index(),
|
||||
self.env.module.info.imported_memories[import_mem_index].1,
|
||||
),
|
||||
};
|
||||
let (namespace, mem_index, description) =
|
||||
match mem_index.local_or_import(&self.env.module.info) {
|
||||
LocalOrImport::Local(local_mem_index) => (
|
||||
call_names::LOCAL_NAMESPACE,
|
||||
local_mem_index.index(),
|
||||
self.env.module.info.memories[local_mem_index],
|
||||
),
|
||||
LocalOrImport::Import(import_mem_index) => (
|
||||
call_names::IMPORT_NAMESPACE,
|
||||
import_mem_index.index(),
|
||||
self.env.module.info.imported_memories[import_mem_index].1,
|
||||
),
|
||||
};
|
||||
|
||||
let name_index = match description.memory_type() {
|
||||
MemoryType::Dynamic => call_names::DYNAMIC_MEM_SIZE,
|
||||
|
@ -136,7 +136,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
||||
// assert!(!desc.mutable);
|
||||
let global_index: GlobalIndex = Converter(global_index).into();
|
||||
let imported_global_index = global_index
|
||||
.local_or_import(self.module)
|
||||
.local_or_import(&self.module.info)
|
||||
.import()
|
||||
.expect("invalid global initializer when declaring an imported global");
|
||||
Initializer::GetGlobal(imported_global_index)
|
||||
@ -246,7 +246,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
||||
let base = match base {
|
||||
Some(global_index) => {
|
||||
let global_index: GlobalIndex = Converter(global_index).into();
|
||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
||||
Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||
LocalOrImport::Local(_) => {
|
||||
panic!("invalid global initializer when declaring an imported global")
|
||||
@ -316,7 +316,7 @@ impl<'module, 'isa, 'data> ModuleEnvironment<'data> for ModuleEnv<'module, 'isa>
|
||||
let base = match base {
|
||||
Some(global_index) => {
|
||||
let global_index: GlobalIndex = Converter(global_index).into();
|
||||
Initializer::GetGlobal(match global_index.local_or_import(self.module) {
|
||||
Initializer::GetGlobal(match global_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Import(imported_global_index) => imported_global_index,
|
||||
LocalOrImport::Local(_) => {
|
||||
panic!("invalid global initializer when declaring an imported global")
|
||||
|
@ -148,7 +148,7 @@ fn get_func_from_index<'a>(
|
||||
.get(func_index)
|
||||
.expect("broken invariant, incorrect func index");
|
||||
|
||||
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
||||
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
|
1
lib/llvm-backend/.llvmenv
Normal file
1
lib/llvm-backend/.llvmenv
Normal file
@ -0,0 +1 @@
|
||||
/usr/local/opt/llvm/bin
|
17
lib/llvm-backend/Cargo.toml
Normal file
17
lib/llvm-backend/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "llvm-backend"
|
||||
version = "0.1.0"
|
||||
authors = ["Lachlan Sneff <lachlan.sneff@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
wasmer-runtime-core = { path = "../runtime-core", version = "0.1.2" }
|
||||
wasmparser = "0.28.0"
|
||||
inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm7-0" }
|
||||
hashbrown = "0.1.8"
|
||||
|
||||
[dev-dependencies]
|
||||
wabt = "0.7.4"
|
||||
|
||||
[features]
|
||||
debug = ["wasmer-runtime-core/debug"]
|
765
lib/llvm-backend/src/code.rs
Normal file
765
lib/llvm-backend/src/code.rs
Normal file
@ -0,0 +1,765 @@
|
||||
use hashbrown::HashMap;
|
||||
use inkwell::{
|
||||
basic_block::BasicBlock,
|
||||
builder::Builder,
|
||||
context::Context,
|
||||
module::Module,
|
||||
types::{BasicType, BasicTypeEnum, FunctionType},
|
||||
values::{AggregateValue, BasicValue, BasicValueEnum, FunctionValue},
|
||||
IntPredicate,
|
||||
};
|
||||
use wasmer_runtime_core::{
|
||||
module::ModuleInfo,
|
||||
structures::{Map, SliceMap, TypedIndex},
|
||||
types::{FuncIndex, FuncSig, LocalFuncIndex, LocalOrImport, SigIndex, Type},
|
||||
};
|
||||
use wasmparser::{BinaryReaderError, CodeSectionReader, LocalsReader, Operator, OperatorsReader};
|
||||
|
||||
use crate::intrinsics::Intrinsics;
|
||||
use crate::read_info::type_to_type;
|
||||
use crate::state::State;
|
||||
|
||||
fn func_sig_to_llvm(context: &Context, sig: &FuncSig) -> FunctionType {
|
||||
let param_types: Vec<_> = sig
|
||||
.params()
|
||||
.iter()
|
||||
.map(|&ty| type_to_llvm(context, ty))
|
||||
.collect();
|
||||
|
||||
match sig.returns() {
|
||||
[] => context.void_type().fn_type(¶m_types, false),
|
||||
[single_value] => type_to_llvm(context, *single_value).fn_type(¶m_types, false),
|
||||
returns @ _ => {
|
||||
let basic_types: Vec<_> = returns
|
||||
.iter()
|
||||
.map(|&ty| type_to_llvm(context, ty))
|
||||
.collect();
|
||||
|
||||
context
|
||||
.struct_type(&basic_types, false)
|
||||
.fn_type(¶m_types, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn type_to_llvm(context: &Context, ty: Type) -> BasicTypeEnum {
|
||||
match ty {
|
||||
Type::I32 => context.i32_type().as_basic_type_enum(),
|
||||
Type::I64 => context.i64_type().as_basic_type_enum(),
|
||||
Type::F32 => context.f32_type().as_basic_type_enum(),
|
||||
Type::F64 => context.f64_type().as_basic_type_enum(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_function_bodies(
|
||||
info: &ModuleInfo,
|
||||
code_reader: CodeSectionReader,
|
||||
) -> Result<(), BinaryReaderError> {
|
||||
let context = Context::create();
|
||||
let module = context.create_module("module");
|
||||
let builder = context.create_builder();
|
||||
|
||||
let intrinsics = Intrinsics::declare(&module, &context);
|
||||
|
||||
let signatures: Map<SigIndex, FunctionType> = info
|
||||
.signatures
|
||||
.iter()
|
||||
.map(|(_, sig)| func_sig_to_llvm(&context, sig))
|
||||
.collect();
|
||||
let functions: Map<LocalFuncIndex, FunctionValue> = info
|
||||
.func_assoc
|
||||
.iter()
|
||||
.skip(info.imported_functions.len())
|
||||
.map(|(func_index, &sig_index)| {
|
||||
module.add_function(
|
||||
&format!("fn:{}", func_index.index()),
|
||||
signatures[sig_index],
|
||||
None,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
for (local_func_index, body) in code_reader.into_iter().enumerate() {
|
||||
let body = body?;
|
||||
|
||||
let locals_reader = body.get_locals_reader()?;
|
||||
let op_reader = body.get_operators_reader()?;
|
||||
|
||||
parse_function(
|
||||
&context,
|
||||
&module,
|
||||
&builder,
|
||||
&intrinsics,
|
||||
info,
|
||||
&signatures,
|
||||
&functions,
|
||||
LocalFuncIndex::new(local_func_index),
|
||||
locals_reader,
|
||||
op_reader,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_function(
|
||||
context: &Context,
|
||||
module: &Module,
|
||||
builder: &Builder,
|
||||
intrinsics: &Intrinsics,
|
||||
info: &ModuleInfo,
|
||||
signatures: &SliceMap<SigIndex, FunctionType>,
|
||||
functions: &SliceMap<LocalFuncIndex, FunctionValue>,
|
||||
func_index: LocalFuncIndex,
|
||||
locals_reader: LocalsReader,
|
||||
op_reader: OperatorsReader,
|
||||
) -> Result<(), BinaryReaderError> {
|
||||
let llvm_sig = &signatures[info.func_assoc[func_index.convert_up(info)]];
|
||||
|
||||
let function = functions[func_index];
|
||||
let entry_block = context.append_basic_block(&function, "entry");
|
||||
builder.position_at_end(&entry_block);
|
||||
|
||||
let mut state = State::new();
|
||||
|
||||
let mut locals = Vec::with_capacity(locals_reader.get_count() as usize);
|
||||
locals.extend(function.get_param_iter().enumerate().map(|(index, param)| {
|
||||
let ty = param.get_type();
|
||||
|
||||
let alloca = builder.build_alloca(ty, &state.var_name());
|
||||
builder.build_store(alloca, param);
|
||||
alloca
|
||||
}));
|
||||
|
||||
for (index, local) in locals_reader.into_iter().enumerate().skip(locals.len()) {
|
||||
let (_, ty) = local?;
|
||||
|
||||
let wasmer_ty = type_to_type(ty)?;
|
||||
|
||||
let ty = type_to_llvm(context, wasmer_ty);
|
||||
|
||||
let alloca = builder.build_alloca(ty, &state.var_name());
|
||||
|
||||
let default_value = match wasmer_ty {
|
||||
Type::I32 => context.i32_type().const_int(0, false).as_basic_value_enum(),
|
||||
Type::I64 => context.i64_type().const_int(0, false).as_basic_value_enum(),
|
||||
Type::F32 => context.f32_type().const_float(0.0).as_basic_value_enum(),
|
||||
Type::F64 => context.f64_type().const_float(0.0).as_basic_value_enum(),
|
||||
};
|
||||
|
||||
builder.build_store(alloca, default_value);
|
||||
|
||||
locals.push(alloca);
|
||||
}
|
||||
|
||||
for op in op_reader {
|
||||
match op? {
|
||||
/***************************
|
||||
* Basic instructions.
|
||||
* https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#basic-instructions
|
||||
***************************/
|
||||
Operator::Nop => {
|
||||
// Do nothing.
|
||||
}
|
||||
Operator::Drop => {
|
||||
state.pop1()?;
|
||||
}
|
||||
|
||||
// Generate const values.
|
||||
Operator::I32Const { value } => {
|
||||
let i = context.i32_type().const_int(value as u64, false);
|
||||
state.push1(i);
|
||||
}
|
||||
Operator::I64Const { value } => {
|
||||
let i = context.i64_type().const_int(value as u64, false);
|
||||
state.push1(i);
|
||||
}
|
||||
Operator::F32Const { value } => {
|
||||
let f = context
|
||||
.f32_type()
|
||||
.const_float(f64::from_bits(value.bits() as u64));
|
||||
state.push1(f);
|
||||
}
|
||||
Operator::F64Const { value } => {
|
||||
let f = context.f64_type().const_float(f64::from_bits(value.bits()));
|
||||
state.push1(f);
|
||||
}
|
||||
|
||||
// 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());
|
||||
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);
|
||||
}
|
||||
Operator::TeeLocal { local_index } => {
|
||||
let pointer_value = locals[local_index as usize];
|
||||
let v = state.peek1()?;
|
||||
builder.build_store(pointer_value, v);
|
||||
}
|
||||
|
||||
Operator::GetGlobal { global_index } => unimplemented!(),
|
||||
Operator::SetGlobal { global_index } => unimplemented!(),
|
||||
|
||||
Operator::Select => {
|
||||
let (v1, v2, cond) = state.pop3()?;
|
||||
let cond = cond.into_int_value();
|
||||
let res = builder.build_select(cond, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::Call { function_index } => {
|
||||
let func_index = FuncIndex::new(function_index as usize);
|
||||
let sigindex = info.func_assoc[func_index];
|
||||
let llvm_sig = signatures[sigindex];
|
||||
|
||||
match func_index.local_or_import(info) {
|
||||
LocalOrImport::Local(local_func_index) => {
|
||||
let func_sig = &info.signatures[sigindex];
|
||||
let func_value = functions[local_func_index];
|
||||
let call_site = builder.build_call(
|
||||
func_value,
|
||||
&state.peekn(func_sig.params().len())?.to_vec(),
|
||||
&state.var_name(),
|
||||
);
|
||||
if let Some(basic_value) = call_site.try_as_basic_value().left() {
|
||||
match func_sig.returns().len() {
|
||||
1 => state.push1(basic_value),
|
||||
count @ _ => {
|
||||
// This is a multi-value return.
|
||||
let struct_value = basic_value.into_struct_value();
|
||||
for i in 0..(count as u32) {
|
||||
let value = builder.build_extract_value(
|
||||
struct_value,
|
||||
i,
|
||||
&state.var_name(),
|
||||
);
|
||||
state.push1(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(import_func_index) => {
|
||||
// unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Operator::CallIndirect { index, table_index } => {
|
||||
unimplemented!("{}, {}", index, table_index);
|
||||
}
|
||||
|
||||
/***************************
|
||||
* Integer Arithmetic instructions.
|
||||
* https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-arithmetic-instructions
|
||||
***************************/
|
||||
Operator::I32Add | Operator::I64Add => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_add(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32Sub | Operator::I64Sub => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_sub(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32Mul | Operator::I64Mul => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_mul(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32DivS | Operator::I64DivS => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_signed_div(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32DivU | Operator::I64DivU => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_unsigned_div(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32RemS | Operator::I64RemS => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_signed_rem(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32RemU | Operator::I64RemU => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_unsigned_rem(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32And | Operator::I64And => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
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 => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
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 => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
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::I32Shl | Operator::I64Shl => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_left_shift(v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32ShrS | Operator::I64ShrS => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_right_shift(v1, v2, true, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32ShrU | Operator::I64ShrU => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_right_shift(v1, v2, false, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32Rotl => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let lhs = builder.build_left_shift(v1, v2, &state.var_name());
|
||||
let rhs = {
|
||||
let int_width = context.i32_type().const_int(32 as u64, false);
|
||||
let rhs = builder.build_int_sub(int_width, v2, &state.var_name());
|
||||
builder.build_right_shift(v1, rhs, false, &state.var_name())
|
||||
};
|
||||
let res = builder.build_or(lhs, rhs, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I64Rotl => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let lhs = builder.build_left_shift(v1, v2, &state.var_name());
|
||||
let rhs = {
|
||||
let int_width = context.i64_type().const_int(64 as u64, false);
|
||||
let rhs = builder.build_int_sub(int_width, v2, &state.var_name());
|
||||
builder.build_right_shift(v1, rhs, false, &state.var_name())
|
||||
};
|
||||
let res = builder.build_or(lhs, rhs, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32Rotr => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let lhs = builder.build_right_shift(v1, v2, false, &state.var_name());
|
||||
let rhs = {
|
||||
let int_width = context.i32_type().const_int(32 as u64, false);
|
||||
let rhs = builder.build_int_sub(int_width, v2, &state.var_name());
|
||||
builder.build_left_shift(v1, rhs, &state.var_name())
|
||||
};
|
||||
let res = builder.build_or(lhs, rhs, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I64Rotr => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let lhs = builder.build_right_shift(v1, v2, false, &state.var_name());
|
||||
let rhs = {
|
||||
let int_width = context.i64_type().const_int(64 as u64, false);
|
||||
let rhs = builder.build_int_sub(int_width, v2, &state.var_name());
|
||||
builder.build_left_shift(v1, rhs, &state.var_name())
|
||||
};
|
||||
let res = builder.build_or(lhs, rhs, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32Clz => {
|
||||
let input = state.pop1()?;
|
||||
let ensure_defined_zero = context
|
||||
.bool_type()
|
||||
.const_int(1 as u64, false)
|
||||
.as_basic_value_enum();
|
||||
let res = builder
|
||||
.build_call(
|
||||
intrinsics.ctlz_i32,
|
||||
&[input, ensure_defined_zero],
|
||||
&state.var_name(),
|
||||
)
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I64Clz => {
|
||||
let input = state.pop1()?;
|
||||
let ensure_defined_zero = context
|
||||
.bool_type()
|
||||
.const_int(1 as u64, false)
|
||||
.as_basic_value_enum();
|
||||
let res = builder
|
||||
.build_call(
|
||||
intrinsics.ctlz_i64,
|
||||
&[input, ensure_defined_zero],
|
||||
&state.var_name(),
|
||||
)
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32Ctz => {
|
||||
let input = state.pop1()?;
|
||||
let ensure_defined_zero = context
|
||||
.bool_type()
|
||||
.const_int(1 as u64, false)
|
||||
.as_basic_value_enum();
|
||||
let res = builder
|
||||
.build_call(
|
||||
intrinsics.cttz_i32,
|
||||
&[input, ensure_defined_zero],
|
||||
&state.var_name(),
|
||||
)
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I64Ctz => {
|
||||
let input = state.pop1()?;
|
||||
let ensure_defined_zero = context
|
||||
.bool_type()
|
||||
.const_int(1 as u64, false)
|
||||
.as_basic_value_enum();
|
||||
let res = builder
|
||||
.build_call(
|
||||
intrinsics.cttz_i64,
|
||||
&[input, ensure_defined_zero],
|
||||
&state.var_name(),
|
||||
)
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32Popcnt => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.ctpop_i32, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I64Popcnt => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.ctpop_i64, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32Eqz => {
|
||||
let input = state.pop1()?.into_int_value();
|
||||
let zero = context.i32_type().const_int(0, false);
|
||||
let res =
|
||||
builder.build_int_compare(IntPredicate::EQ, input, zero, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I64Eqz => {
|
||||
let input = state.pop1()?.into_int_value();
|
||||
let zero = context.i64_type().const_int(0, false);
|
||||
let res =
|
||||
builder.build_int_compare(IntPredicate::EQ, input, zero, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
|
||||
/***************************
|
||||
* Floating-Point Arithmetic instructions.
|
||||
* https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-arithmetic-instructions
|
||||
***************************/
|
||||
Operator::F32Add | 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(res);
|
||||
}
|
||||
Operator::F32Sub | Operator::F32Sub => {
|
||||
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(res);
|
||||
}
|
||||
Operator::F32Mul | 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(res);
|
||||
}
|
||||
Operator::F32Div | 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(res);
|
||||
}
|
||||
Operator::F32Sqrt => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.sqrt_f32, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F64Sqrt => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.sqrt_f64, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F32Min => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.minimum_f32, &[v1, v2], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F64Min => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.minimum_f64, &[v1, v2], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F32Max => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.maximum_f32, &[v1, v2], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F64Max => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.maximum_f64, &[v1, v2], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F32Ceil => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.ceil_f32, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F64Ceil => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.ceil_f64, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F32Floor => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.floor_f32, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F64Floor => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.floor_f64, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F32Trunc => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.trunc_f32, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F64Trunc => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.trunc_f64, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F32Nearest => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.nearbyint_f32, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F64Nearest => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.nearbyint_f64, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F32Abs => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.fabs_f32, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F64Abs => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.fabs_f64, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F32Neg | Operator::F64Neg => {
|
||||
let input = state.pop1()?.into_float_value();
|
||||
let res = builder.build_float_neg(input, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F32Copysign => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.copysign_f32, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::F64Copysign => {
|
||||
let input = state.pop1()?;
|
||||
let res = builder
|
||||
.build_call(intrinsics.copysign_f64, &[input], &state.var_name())
|
||||
.try_as_basic_value()
|
||||
.left()
|
||||
.unwrap();
|
||||
state.push1(res);
|
||||
}
|
||||
|
||||
/***************************
|
||||
* Integer Comparison instructions.
|
||||
* https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-comparison-instructions
|
||||
***************************/
|
||||
Operator::I32Eq | Operator::I64Eq => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::EQ, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32Ne | Operator::I64Ne => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::NE, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32LtS | Operator::I64LtS => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::SLT, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32LtU | Operator::I64LtU => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::ULT, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32LeS | Operator::I64LeS => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::SLE, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32LeU | Operator::I64LeU => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::ULE, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32GtS | Operator::I64GtS => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::SGT, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32GtU | Operator::I64GtU => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::UGT, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32GeS | Operator::I64GeS => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::SGE, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
Operator::I32GeU | Operator::I64GeU => {
|
||||
let (v1, v2) = state.pop2()?;
|
||||
let (v1, v2) = (v1.into_int_value(), v2.into_int_value());
|
||||
let res = builder.build_int_compare(IntPredicate::UGE, v1, v2, &state.var_name());
|
||||
state.push1(res);
|
||||
}
|
||||
|
||||
/***************************
|
||||
* Floating-Point Comparison instructions.
|
||||
* https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-comparison-instructions
|
||||
***************************/
|
||||
Operator::Unreachable => {
|
||||
// Emit an unreachable instruction.
|
||||
// If llvm cannot prove that this is never touched,
|
||||
// it will emit a `ud2` instruction on x86_64 arches.
|
||||
builder.build_unreachable();
|
||||
}
|
||||
op @ _ => {
|
||||
println!("{}", module.print_to_string().to_string());
|
||||
unimplemented!("{:?}", op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
61
lib/llvm-backend/src/example.rs
Normal file
61
lib/llvm-backend/src/example.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use inkwell::OptimizationLevel;
|
||||
use inkwell::builder::Builder;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::execution_engine::{ExecutionEngine, JitFunction};
|
||||
use inkwell::module::Module;
|
||||
use inkwell::targets::{InitializationConfig, Target};
|
||||
use std::error::Error;
|
||||
|
||||
/// Convenience type alias for the `sum` function.
|
||||
///
|
||||
/// Calling this is innately `unsafe` because there's no guarantee it doesn't
|
||||
/// do `unsafe` operations internally.
|
||||
type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64;
|
||||
|
||||
#[test]
|
||||
fn test_sum() -> Result<(), Box<Error>> {
|
||||
let context = Context::create();
|
||||
let module = context.create_module("sum");
|
||||
let builder = context.create_builder();
|
||||
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::Aggressive)?;
|
||||
|
||||
let sum = jit_compile_sum(&context, &module, &builder, &execution_engine)
|
||||
.ok_or("Unable to JIT compile `sum`")?;
|
||||
|
||||
let x = 1u64;
|
||||
let y = 2u64;
|
||||
let z = 3u64;
|
||||
|
||||
unsafe {
|
||||
println!("{} + {} + {} = {}", x, y, z, sum.call(x, y, z));
|
||||
assert_eq!(sum.call(x, y, z), x + y + z);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn jit_compile_sum(
|
||||
context: &Context,
|
||||
module: &Module,
|
||||
builder: &Builder,
|
||||
execution_engine: &ExecutionEngine,
|
||||
) -> Option<JitFunction<SumFunc>> {
|
||||
let i64_type = context.i64_type();
|
||||
let fn_type = i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false);
|
||||
|
||||
let function = module.add_function("sum", fn_type, None);
|
||||
let basic_block = context.append_basic_block(&function, "entry");
|
||||
|
||||
builder.position_at_end(&basic_block);
|
||||
|
||||
let x = function.get_nth_param(0)?.into_int_value();
|
||||
let y = function.get_nth_param(1)?.into_int_value();
|
||||
let z = function.get_nth_param(2)?.into_int_value();
|
||||
|
||||
let sum = builder.build_int_add(x, y, "sum");
|
||||
let sum = builder.build_int_add(sum, z, "sum");
|
||||
|
||||
builder.build_return(Some(&sum));
|
||||
|
||||
unsafe { execution_engine.get_function("sum").ok() }
|
||||
}
|
99
lib/llvm-backend/src/intrinsics.rs
Normal file
99
lib/llvm-backend/src/intrinsics.rs
Normal file
@ -0,0 +1,99 @@
|
||||
use inkwell::{context::Context, module::Module, types::BasicType, values::FunctionValue};
|
||||
|
||||
pub struct Intrinsics {
|
||||
pub ctlz_i32: FunctionValue,
|
||||
pub ctlz_i64: FunctionValue,
|
||||
|
||||
pub cttz_i32: FunctionValue,
|
||||
pub cttz_i64: FunctionValue,
|
||||
|
||||
pub ctpop_i32: FunctionValue,
|
||||
pub ctpop_i64: FunctionValue,
|
||||
|
||||
pub sqrt_f32: FunctionValue,
|
||||
pub sqrt_f64: FunctionValue,
|
||||
|
||||
pub minimum_f32: FunctionValue,
|
||||
pub minimum_f64: FunctionValue,
|
||||
|
||||
pub maximum_f32: FunctionValue,
|
||||
pub maximum_f64: FunctionValue,
|
||||
|
||||
pub ceil_f32: FunctionValue,
|
||||
pub ceil_f64: FunctionValue,
|
||||
|
||||
pub floor_f32: FunctionValue,
|
||||
pub floor_f64: FunctionValue,
|
||||
|
||||
pub trunc_f32: FunctionValue,
|
||||
pub trunc_f64: FunctionValue,
|
||||
|
||||
pub nearbyint_f32: FunctionValue,
|
||||
pub nearbyint_f64: FunctionValue,
|
||||
|
||||
pub fabs_f32: FunctionValue,
|
||||
pub fabs_f64: FunctionValue,
|
||||
|
||||
pub copysign_f32: FunctionValue,
|
||||
pub copysign_f64: FunctionValue,
|
||||
}
|
||||
|
||||
impl Intrinsics {
|
||||
pub fn declare(module: &Module, context: &Context) -> Self {
|
||||
let i1_ty = context.bool_type().as_basic_type_enum();
|
||||
let i32_ty = context.i32_type().as_basic_type_enum();
|
||||
let i64_ty = context.i64_type().as_basic_type_enum();
|
||||
let f32_ty = context.f32_type().as_basic_type_enum();
|
||||
let f64_ty = context.f64_type().as_basic_type_enum();
|
||||
|
||||
let ret_i32_take_i32_i1 = i32_ty.fn_type(&[i32_ty, i1_ty], false);
|
||||
let ret_i64_take_i64_i1 = i64_ty.fn_type(&[i64_ty, i1_ty], false);
|
||||
|
||||
let ret_i32_take_i32 = i32_ty.fn_type(&[i32_ty], false);
|
||||
let ret_i64_take_i64 = i64_ty.fn_type(&[i64_ty], false);
|
||||
|
||||
let ret_f32_take_f32 = f32_ty.fn_type(&[f32_ty], false);
|
||||
let ret_f64_take_f64 = f64_ty.fn_type(&[f64_ty], false);
|
||||
|
||||
let ret_f32_take_f32_f32 = f32_ty.fn_type(&[f32_ty, f32_ty], false);
|
||||
let ret_f64_take_f64_f64 = f64_ty.fn_type(&[f64_ty, f64_ty], false);
|
||||
|
||||
Self {
|
||||
ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
|
||||
ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None),
|
||||
|
||||
cttz_i32: module.add_function("llvm.cttz.i32", ret_i32_take_i32_i1, None),
|
||||
cttz_i64: module.add_function("llvm.cttz.i64", ret_i64_take_i64_i1, None),
|
||||
|
||||
ctpop_i32: module.add_function("llvm.ctpop.i32", ret_i32_take_i32, None),
|
||||
ctpop_i64: module.add_function("llvm.ctpop.i64", ret_i64_take_i64, None),
|
||||
|
||||
sqrt_f32: module.add_function("llvm.sqrt.f32", ret_f32_take_f32, None),
|
||||
sqrt_f64: module.add_function("llvm.sqrt.f64", ret_f64_take_f64, None),
|
||||
|
||||
minimum_f32: module.add_function("llvm.minimum.f32", ret_f32_take_f32_f32, None),
|
||||
minimum_f64: module.add_function("llvm.minimum.f64", ret_f64_take_f64_f64, None),
|
||||
|
||||
maximum_f32: module.add_function("llvm.maximum.f32", ret_f32_take_f32_f32, None),
|
||||
maximum_f64: module.add_function("llvm.maximum.f64", ret_f64_take_f64_f64, 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),
|
||||
|
||||
floor_f32: module.add_function("llvm.floor.f32", ret_f32_take_f32, None),
|
||||
floor_f64: module.add_function("llvm.floor.f64", ret_f64_take_f64, None),
|
||||
|
||||
trunc_f32: module.add_function("llvm.trunc.f32", ret_f32_take_f32, None),
|
||||
trunc_f64: module.add_function("llvm.trunc.f64", ret_f64_take_f64, None),
|
||||
|
||||
nearbyint_f32: module.add_function("llvm.nearbyint.f32", ret_f32_take_f32, None),
|
||||
nearbyint_f64: module.add_function("llvm.nearbyint.f64", ret_f64_take_f64, None),
|
||||
|
||||
fabs_f32: module.add_function("llvm.fabs.f32", ret_f32_take_f32, None),
|
||||
fabs_f64: module.add_function("llvm.fabs.f64", ret_f64_take_f64, None),
|
||||
|
||||
copysign_f32: module.add_function("llvm.copysign.f32", ret_f32_take_f32_f32, None),
|
||||
copysign_f64: module.add_function("llvm.copysign.f64", ret_f64_take_f64_f64, None),
|
||||
}
|
||||
}
|
||||
}
|
52
lib/llvm-backend/src/lib.rs
Normal file
52
lib/llvm-backend/src/lib.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use wasmer_runtime_core::{
|
||||
backend::{Compiler, Token},
|
||||
error::CompileError,
|
||||
module::{ModuleInfo, ModuleInner},
|
||||
};
|
||||
|
||||
mod code;
|
||||
mod intrinsics;
|
||||
mod read_info;
|
||||
mod state;
|
||||
|
||||
pub struct LLVMCompiler {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl LLVMCompiler {
|
||||
pub fn new() -> Self {
|
||||
Self { _private: () }
|
||||
}
|
||||
}
|
||||
|
||||
impl Compiler for LLVMCompiler {
|
||||
fn compile(&self, wasm: &[u8], _: Token) -> Result<ModuleInner, CompileError> {
|
||||
let (_info, _code_reader) = read_info::read_module(wasm).unwrap();
|
||||
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_module() {
|
||||
use wabt::wat2wasm;
|
||||
let WAT: &'static str = r#"
|
||||
(module
|
||||
(type $t0 (func (param i32) (result i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
(import "env" "table" (table 10 anyfunc))
|
||||
(import "env" "global" (global i32))
|
||||
(import "env" "print_i32" (func $print_i32 (type $t0)))
|
||||
(func $identity (type $t0) (param $p0 i32) (result i32)
|
||||
get_local $p0)
|
||||
(func $print_num (export "print_num") (type $t0) (param $p0 i32) (result i32)
|
||||
get_global 0
|
||||
call $identity
|
||||
call $print_i32))
|
||||
"#;
|
||||
let wasm = wat2wasm(WAT).unwrap();
|
||||
|
||||
let (info, code_reader) = read_info::read_module(&wasm).unwrap();
|
||||
|
||||
code::parse_function_bodies(&info, code_reader).unwrap();
|
||||
}
|
333
lib/llvm-backend/src/read_info.rs
Normal file
333
lib/llvm-backend/src/read_info.rs
Normal file
@ -0,0 +1,333 @@
|
||||
use wasmer_runtime_core::{
|
||||
backend::Backend,
|
||||
module::{
|
||||
DataInitializer, ExportIndex, ImportName, ModuleInfo, StringTable, StringTableBuilder,
|
||||
TableInitializer,
|
||||
},
|
||||
structures::{Map, TypedIndex},
|
||||
types::{
|
||||
ElementType, FuncIndex, FuncSig, GlobalDescriptor, GlobalIndex, GlobalInit,
|
||||
ImportedGlobalIndex, Initializer, MemoryDescriptor, MemoryIndex, SigIndex, TableDescriptor,
|
||||
TableIndex, Type, Value,
|
||||
},
|
||||
units::Pages,
|
||||
};
|
||||
use wasmparser::{
|
||||
BinaryReaderError, CodeSectionReader, Data, DataKind, Element, ElementKind, Export,
|
||||
ExternalKind, FuncType, Import, ImportSectionEntryType, InitExpr, ModuleReader, Operator,
|
||||
SectionCode, Type as WpType,
|
||||
};
|
||||
|
||||
pub fn read_module(wasm: &[u8]) -> Result<(ModuleInfo, CodeSectionReader), BinaryReaderError> {
|
||||
let mut info = ModuleInfo {
|
||||
memories: Map::new(),
|
||||
globals: Map::new(),
|
||||
tables: Map::new(),
|
||||
|
||||
imported_functions: Map::new(),
|
||||
imported_memories: Map::new(),
|
||||
imported_tables: Map::new(),
|
||||
imported_globals: Map::new(),
|
||||
|
||||
exports: Default::default(),
|
||||
|
||||
data_initializers: Vec::new(),
|
||||
elem_initializers: Vec::new(),
|
||||
|
||||
start_func: None,
|
||||
|
||||
func_assoc: Map::new(),
|
||||
signatures: Map::new(),
|
||||
backend: Backend::LLVM,
|
||||
|
||||
namespace_table: StringTable::new(),
|
||||
name_table: StringTable::new(),
|
||||
};
|
||||
|
||||
let mut reader = ModuleReader::new(wasm)?;
|
||||
let mut code_reader = None;
|
||||
|
||||
loop {
|
||||
if reader.eof() {
|
||||
return Ok((info, code_reader.unwrap()));
|
||||
}
|
||||
|
||||
let section = reader.read()?;
|
||||
|
||||
match section.code {
|
||||
SectionCode::Type => {
|
||||
let type_reader = section.get_type_section_reader()?;
|
||||
|
||||
for ty in type_reader {
|
||||
let ty = ty?;
|
||||
info.signatures.push(func_type_to_func_sig(ty)?);
|
||||
}
|
||||
}
|
||||
SectionCode::Import => {
|
||||
let import_reader = section.get_import_section_reader()?;
|
||||
let mut namespace_builder = StringTableBuilder::new();
|
||||
let mut name_builder = StringTableBuilder::new();
|
||||
|
||||
for import in import_reader {
|
||||
let Import { module, field, ty } = import?;
|
||||
|
||||
let namespace_index = namespace_builder.register(module);
|
||||
let name_index = name_builder.register(field);
|
||||
let import_name = ImportName {
|
||||
namespace_index,
|
||||
name_index,
|
||||
};
|
||||
|
||||
match ty {
|
||||
ImportSectionEntryType::Function(sigindex) => {
|
||||
let sigindex = SigIndex::new(sigindex as usize);
|
||||
info.imported_functions.push(import_name);
|
||||
info.func_assoc.push(sigindex);
|
||||
}
|
||||
ImportSectionEntryType::Table(table_ty) => {
|
||||
assert_eq!(table_ty.element_type, WpType::AnyFunc);
|
||||
let table_desc = TableDescriptor {
|
||||
element: ElementType::Anyfunc,
|
||||
minimum: table_ty.limits.initial,
|
||||
maximum: table_ty.limits.maximum,
|
||||
};
|
||||
|
||||
info.imported_tables.push((import_name, table_desc));
|
||||
}
|
||||
ImportSectionEntryType::Memory(memory_ty) => {
|
||||
let mem_desc = MemoryDescriptor {
|
||||
minimum: Pages(memory_ty.limits.initial),
|
||||
maximum: memory_ty.limits.maximum.map(|max| Pages(max)),
|
||||
shared: memory_ty.shared,
|
||||
};
|
||||
info.imported_memories.push((import_name, mem_desc));
|
||||
}
|
||||
ImportSectionEntryType::Global(global_ty) => {
|
||||
let global_desc = GlobalDescriptor {
|
||||
mutable: global_ty.mutable,
|
||||
ty: type_to_type(global_ty.content_type)?,
|
||||
};
|
||||
info.imported_globals.push((import_name, global_desc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionCode::Function => {
|
||||
let func_decl_reader = section.get_function_section_reader()?;
|
||||
|
||||
for sigindex in func_decl_reader {
|
||||
let sigindex = sigindex?;
|
||||
|
||||
let sigindex = SigIndex::new(sigindex as usize);
|
||||
info.func_assoc.push(sigindex);
|
||||
}
|
||||
}
|
||||
SectionCode::Table => {
|
||||
let table_decl_reader = section.get_table_section_reader()?;
|
||||
|
||||
for table_ty in table_decl_reader {
|
||||
let table_ty = table_ty?;
|
||||
|
||||
let table_desc = TableDescriptor {
|
||||
element: ElementType::Anyfunc,
|
||||
minimum: table_ty.limits.initial,
|
||||
maximum: table_ty.limits.maximum,
|
||||
};
|
||||
|
||||
info.tables.push(table_desc);
|
||||
}
|
||||
}
|
||||
SectionCode::Memory => {
|
||||
let mem_decl_reader = section.get_memory_section_reader()?;
|
||||
|
||||
for memory_ty in mem_decl_reader {
|
||||
let memory_ty = memory_ty?;
|
||||
|
||||
let mem_desc = MemoryDescriptor {
|
||||
minimum: Pages(memory_ty.limits.initial),
|
||||
maximum: memory_ty.limits.maximum.map(|max| Pages(max)),
|
||||
shared: memory_ty.shared,
|
||||
};
|
||||
|
||||
info.memories.push(mem_desc);
|
||||
}
|
||||
}
|
||||
SectionCode::Global => {
|
||||
let global_decl_reader = section.get_global_section_reader()?;
|
||||
|
||||
for global in global_decl_reader {
|
||||
let global = global?;
|
||||
|
||||
let desc = GlobalDescriptor {
|
||||
mutable: global.ty.mutable,
|
||||
ty: type_to_type(global.ty.content_type)?,
|
||||
};
|
||||
|
||||
let global_init = GlobalInit {
|
||||
desc,
|
||||
init: eval_init_expr(&global.init_expr)?,
|
||||
};
|
||||
|
||||
info.globals.push(global_init);
|
||||
}
|
||||
}
|
||||
SectionCode::Export => {
|
||||
let export_reader = section.get_export_section_reader()?;
|
||||
|
||||
for export in export_reader {
|
||||
let Export { field, kind, index } = export?;
|
||||
|
||||
let export_index = match kind {
|
||||
ExternalKind::Function => ExportIndex::Func(FuncIndex::new(index as usize)),
|
||||
ExternalKind::Table => ExportIndex::Table(TableIndex::new(index as usize)),
|
||||
ExternalKind::Memory => {
|
||||
ExportIndex::Memory(MemoryIndex::new(index as usize))
|
||||
}
|
||||
ExternalKind::Global => {
|
||||
ExportIndex::Global(GlobalIndex::new(index as usize))
|
||||
}
|
||||
};
|
||||
|
||||
info.exports.insert(field.to_string(), export_index);
|
||||
}
|
||||
}
|
||||
SectionCode::Start => {
|
||||
let start_index = section.get_start_section_content()?;
|
||||
|
||||
info.start_func = Some(FuncIndex::new(start_index as usize));
|
||||
}
|
||||
SectionCode::Element => {
|
||||
let element_reader = section.get_element_section_reader()?;
|
||||
|
||||
for element in element_reader {
|
||||
let Element { kind, items } = element?;
|
||||
|
||||
match kind {
|
||||
ElementKind::Active {
|
||||
table_index,
|
||||
init_expr,
|
||||
} => {
|
||||
let table_index = TableIndex::new(table_index as usize);
|
||||
let base = eval_init_expr(&init_expr)?;
|
||||
let items_reader = items.get_items_reader()?;
|
||||
|
||||
let elements: Vec<_> = items_reader
|
||||
.into_iter()
|
||||
.map(|res| res.map(|index| FuncIndex::new(index as usize)))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let table_init = TableInitializer {
|
||||
table_index,
|
||||
base,
|
||||
elements,
|
||||
};
|
||||
|
||||
info.elem_initializers.push(table_init);
|
||||
}
|
||||
ElementKind::Passive(_ty) => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "passive tables are not yet supported",
|
||||
offset: -1isize as usize,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionCode::Code => {
|
||||
code_reader = Some(section.get_code_section_reader()?);
|
||||
}
|
||||
SectionCode::Data => {
|
||||
let data_reader = section.get_data_section_reader()?;
|
||||
|
||||
for data in data_reader {
|
||||
let Data { kind, data } = data?;
|
||||
|
||||
match kind {
|
||||
DataKind::Active {
|
||||
memory_index,
|
||||
init_expr,
|
||||
} => {
|
||||
let memory_index = MemoryIndex::new(memory_index as usize);
|
||||
let base = eval_init_expr(&init_expr)?;
|
||||
|
||||
let data_init = DataInitializer {
|
||||
memory_index,
|
||||
base,
|
||||
data: data.to_vec(),
|
||||
};
|
||||
|
||||
info.data_initializers.push(data_init);
|
||||
}
|
||||
DataKind::Passive => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "passive memories are not yet supported",
|
||||
offset: -1isize as usize,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SectionCode::DataCount => {}
|
||||
SectionCode::Custom { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
|
||||
Ok(match ty {
|
||||
WpType::I32 => Type::I32,
|
||||
WpType::I64 => Type::I64,
|
||||
WpType::F32 => Type::F32,
|
||||
WpType::F64 => Type::F64,
|
||||
WpType::V128 => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "the wasmer llvm backend does not yet support the simd extension",
|
||||
offset: -1isize as usize,
|
||||
});
|
||||
}
|
||||
_ => panic!("broken invariant, invalid type"),
|
||||
})
|
||||
}
|
||||
|
||||
fn func_type_to_func_sig(func_ty: FuncType) -> Result<FuncSig, BinaryReaderError> {
|
||||
assert_eq!(func_ty.form, WpType::Func);
|
||||
|
||||
Ok(FuncSig::new(
|
||||
func_ty
|
||||
.params
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(type_to_type)
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
func_ty
|
||||
.returns
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(type_to_type)
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
))
|
||||
}
|
||||
|
||||
fn eval_init_expr(expr: &InitExpr) -> Result<Initializer, BinaryReaderError> {
|
||||
let mut reader = expr.get_operators_reader();
|
||||
let (op, offset) = reader.read_with_offset()?;
|
||||
Ok(match op {
|
||||
Operator::GetGlobal { global_index } => {
|
||||
Initializer::GetGlobal(ImportedGlobalIndex::new(global_index as usize))
|
||||
}
|
||||
Operator::I32Const { value } => Initializer::Const(Value::I32(value)),
|
||||
Operator::I64Const { value } => Initializer::Const(Value::I64(value)),
|
||||
Operator::F32Const { value } => {
|
||||
Initializer::Const(Value::F32(f32::from_bits(value.bits())))
|
||||
}
|
||||
Operator::F64Const { value } => {
|
||||
Initializer::Const(Value::F64(f64::from_bits(value.bits())))
|
||||
}
|
||||
_ => {
|
||||
return Err(BinaryReaderError {
|
||||
message: "init expr evaluation failed: unsupported opcode",
|
||||
offset,
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
105
lib/llvm-backend/src/state.rs
Normal file
105
lib/llvm-backend/src/state.rs
Normal file
@ -0,0 +1,105 @@
|
||||
use inkwell::{
|
||||
basic_block::BasicBlock,
|
||||
values::{BasicValue, BasicValueEnum},
|
||||
};
|
||||
use wasmparser::BinaryReaderError;
|
||||
|
||||
enum ControlFrame {
|
||||
If {
|
||||
dest: BasicBlock,
|
||||
stack_size_snapshot: usize,
|
||||
},
|
||||
Block {
|
||||
dest: BasicBlock,
|
||||
stack_size_snapshot: usize,
|
||||
num_ret_values: usize,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
stack: Vec<BasicValueEnum>,
|
||||
control_stack: Vec<ControlFrame>,
|
||||
value_counter: usize,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
stack: vec![],
|
||||
control_stack: vec![],
|
||||
value_counter: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn var_name(&mut self) -> String {
|
||||
let s = self.value_counter.to_string();
|
||||
self.value_counter += 1;
|
||||
s
|
||||
}
|
||||
|
||||
pub fn push1<T: BasicValue>(&mut self, value: T) {
|
||||
self.stack.push(value.as_basic_value_enum())
|
||||
}
|
||||
|
||||
pub fn pop1(&mut self) -> Result<BasicValueEnum, BinaryReaderError> {
|
||||
self.stack.pop().ok_or_else(|| BinaryReaderError {
|
||||
message: "invalid value stack",
|
||||
offset: -1isize as usize,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn pop2(&mut self) -> Result<(BasicValueEnum, BasicValueEnum), BinaryReaderError> {
|
||||
let v2 = self.pop1()?;
|
||||
let v1 = self.pop1()?;
|
||||
Ok((v1, v2))
|
||||
}
|
||||
|
||||
pub fn pop3(
|
||||
&mut self,
|
||||
) -> Result<(BasicValueEnum, BasicValueEnum, BasicValueEnum), BinaryReaderError> {
|
||||
let v3 = self.pop1()?;
|
||||
let v2 = self.pop1()?;
|
||||
let v1 = self.pop1()?;
|
||||
Ok((v1, v2, v3))
|
||||
}
|
||||
|
||||
pub fn peek1(&self) -> Result<BasicValueEnum, BinaryReaderError> {
|
||||
self.stack
|
||||
.get(self.stack.len() - 1)
|
||||
.ok_or_else(|| BinaryReaderError {
|
||||
message: "invalid value stack",
|
||||
offset: -1isize as usize,
|
||||
})
|
||||
.map(|v| *v)
|
||||
}
|
||||
|
||||
pub fn peekn(&self, n: usize) -> Result<&[BasicValueEnum], BinaryReaderError> {
|
||||
self.stack
|
||||
.get(self.stack.len() - n..)
|
||||
.ok_or_else(|| BinaryReaderError {
|
||||
message: "invalid value stack",
|
||||
offset: -1isize as usize,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn popn(&mut self, n: usize) -> Result<(), BinaryReaderError> {
|
||||
if self.stack.len() < n {
|
||||
return Err(BinaryReaderError {
|
||||
message: "invalid value stack",
|
||||
offset: -1isize as usize,
|
||||
});
|
||||
}
|
||||
|
||||
let new_len = self.stack.len() - n;
|
||||
self.stack.truncate(new_len);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn push_block(&mut self, dest: BasicBlock, num_ret_values: usize) {
|
||||
self.control_stack.push(ControlFrame::Block {
|
||||
dest,
|
||||
stack_size_snapshot: self.stack.len(),
|
||||
num_ret_values,
|
||||
});
|
||||
}
|
||||
}
|
@ -91,7 +91,7 @@ impl LocalBacking {
|
||||
}
|
||||
} as usize;
|
||||
|
||||
match init.memory_index.local_or_import(module) {
|
||||
match init.memory_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_memory_index) => {
|
||||
let memory_desc = module.info.memories[local_memory_index];
|
||||
let data_top = init_base + init.data.len();
|
||||
@ -159,7 +159,7 @@ impl LocalBacking {
|
||||
}
|
||||
} as usize;
|
||||
|
||||
match init.table_index.local_or_import(module) {
|
||||
match init.table_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
let table = &tables[local_table_index];
|
||||
|
||||
@ -178,7 +178,7 @@ impl LocalBacking {
|
||||
let sig_id =
|
||||
vm::SigId(SigRegistry.lookup_sig_index(signature).index() as u32);
|
||||
|
||||
let (func, ctx) = match func_index.local_or_import(module) {
|
||||
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
@ -217,7 +217,7 @@ impl LocalBacking {
|
||||
let sig_id =
|
||||
vm::SigId(SigRegistry.lookup_sig_index(signature).index() as u32);
|
||||
|
||||
let (func, ctx) = match func_index.local_or_import(module) {
|
||||
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
@ -366,7 +366,7 @@ fn import_functions(
|
||||
},
|
||||
) in &module.info.imported_functions
|
||||
{
|
||||
let sig_index = module.info.func_assoc[index.convert_up(module)];
|
||||
let sig_index = module.info.func_assoc[index.convert_up(&module.info)];
|
||||
let expected_sig = &module.info.signatures[sig_index];
|
||||
|
||||
let namespace = module.info.namespace_table.get(*namespace_index);
|
||||
|
@ -123,14 +123,14 @@ impl Instance {
|
||||
})?;
|
||||
}
|
||||
|
||||
let ctx = match func_index.local_or_import(&*self.module) {
|
||||
let ctx = match func_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Local(_) => self.inner.vmctx,
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
self.inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||
}
|
||||
};
|
||||
|
||||
let func_ptr = match func_index.local_or_import(&self.module) {
|
||||
let func_ptr = match func_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Local(local_func_index) => self
|
||||
.module
|
||||
.func_resolver
|
||||
@ -291,7 +291,7 @@ impl Instance {
|
||||
})?
|
||||
}
|
||||
|
||||
let vmctx = match func_index.local_or_import(&self.module) {
|
||||
let vmctx = match func_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Local(_) => self.inner.vmctx,
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
self.inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||
@ -358,7 +358,7 @@ impl InstanceInner {
|
||||
.get(func_index)
|
||||
.expect("broken invariant, incorrect func index");
|
||||
|
||||
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
||||
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
@ -384,7 +384,7 @@ impl InstanceInner {
|
||||
}
|
||||
|
||||
fn get_memory_from_index(&self, module: &ModuleInner, mem_index: MemoryIndex) -> Memory {
|
||||
match mem_index.local_or_import(module) {
|
||||
match mem_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_mem_index) => self.backing.memories[local_mem_index].clone(),
|
||||
LocalOrImport::Import(imported_mem_index) => {
|
||||
self.import_backing.memories[imported_mem_index].clone()
|
||||
@ -393,7 +393,7 @@ impl InstanceInner {
|
||||
}
|
||||
|
||||
fn get_global_from_index(&self, module: &ModuleInner, global_index: GlobalIndex) -> Global {
|
||||
match global_index.local_or_import(module) {
|
||||
match global_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_global_index) => {
|
||||
self.backing.globals[local_global_index].clone()
|
||||
}
|
||||
@ -404,7 +404,7 @@ impl InstanceInner {
|
||||
}
|
||||
|
||||
fn get_table_from_index(&self, module: &ModuleInner, table_index: TableIndex) -> Table {
|
||||
match table_index.local_or_import(module) {
|
||||
match table_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_table_index) => {
|
||||
self.backing.tables[local_table_index].clone()
|
||||
}
|
||||
@ -462,7 +462,7 @@ impl<'a> DynFunc<'a> {
|
||||
})?
|
||||
}
|
||||
|
||||
let vmctx = match self.func_index.local_or_import(self.module) {
|
||||
let vmctx = match self.func_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Local(_) => self.instance_inner.vmctx,
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
self.instance_inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||
@ -488,7 +488,7 @@ impl<'a> DynFunc<'a> {
|
||||
}
|
||||
|
||||
pub fn raw(&self) -> *const vm::Func {
|
||||
match self.func_index.local_or_import(self.module) {
|
||||
match self.func_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Local(local_func_index) => self
|
||||
.module
|
||||
.func_resolver
|
||||
|
@ -1,4 +1,9 @@
|
||||
use crate::{memory::MemoryType, module::ModuleInner, structures::TypedIndex, units::Pages};
|
||||
use crate::{
|
||||
memory::MemoryType,
|
||||
module::{ModuleInfo, ModuleInner},
|
||||
structures::TypedIndex,
|
||||
units::Pages,
|
||||
};
|
||||
use std::{borrow::Cow, mem};
|
||||
|
||||
/// Represents a WebAssembly type.
|
||||
@ -340,23 +345,23 @@ define_map_index![
|
||||
macro_rules! define_local_or_import {
|
||||
($ty:ident, $local_ty:ident, $imported_ty:ident, $imports:ident) => {
|
||||
impl $ty {
|
||||
pub fn local_or_import(self, module: &ModuleInner) -> LocalOrImport<$ty> {
|
||||
if self.index() < module.info.$imports.len() {
|
||||
pub fn local_or_import(self, info: &ModuleInfo) -> LocalOrImport<$ty> {
|
||||
if self.index() < info.$imports.len() {
|
||||
LocalOrImport::Import(<Self as LocalImport>::Import::new(self.index()))
|
||||
} else {
|
||||
LocalOrImport::Local(<Self as LocalImport>::Local::new(self.index() - module.info.$imports.len()))
|
||||
LocalOrImport::Local(<Self as LocalImport>::Local::new(self.index() - info.$imports.len()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl $local_ty {
|
||||
pub fn convert_up(self, module: &ModuleInner) -> $ty {
|
||||
$ty ((self.index() + module.info.$imports.len()) as u32)
|
||||
pub fn convert_up(self, info: &ModuleInfo) -> $ty {
|
||||
$ty ((self.index() + info.$imports.len()) as u32)
|
||||
}
|
||||
}
|
||||
|
||||
impl $imported_ty {
|
||||
pub fn convert_up(self, _module: &ModuleInner) -> $ty {
|
||||
pub fn convert_up(self, _module: &ModuleInfo) -> $ty {
|
||||
$ty (self.index() as u32)
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ impl Ctx {
|
||||
pub fn memory(&self, mem_index: u32) -> &Memory {
|
||||
let module = unsafe { &*self.module };
|
||||
let mem_index = MemoryIndex::new(mem_index as usize);
|
||||
match mem_index.local_or_import(module) {
|
||||
match mem_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_mem_index) => unsafe {
|
||||
let local_backing = &*self.local_backing;
|
||||
&local_backing.memories[local_mem_index]
|
||||
|
Loading…
Reference in New Issue
Block a user