From d238d8f39e29f535c81ceab881fd066157450d3d Mon Sep 17 00:00:00 2001 From: Cyrill Leutwiler Date: Fri, 2 Feb 2024 09:10:03 +0100 Subject: [PATCH] custom ir Signed-off-by: Cyrill Leutwiler --- .gitignore | 1 + Cargo.lock | 399 ++- Cargo.toml | 3 + crates/builtins/Cargo.toml | 2 +- crates/builtins/build.rs | 2 +- crates/cli/Cargo.toml | 5 +- crates/cli/src/main.rs | 15 +- crates/{polkavm => codegen}/Cargo.toml | 6 +- crates/codegen/src/lib.rs | 2 + crates/codegen/src/module.rs | 37 + crates/codegen/src/program.rs | 93 + .../Cargo.toml | 3 +- crates/compilation-target/src/environment.rs | 15 + crates/compilation-target/src/lib.rs | 2 + crates/compilation-target/src/target.rs | 27 + crates/environment/src/lib.rs | 1 - crates/ir/Cargo.toml | 4 +- crates/ir/src/address.rs | 6 +- crates/ir/src/analysis/control_flow.rs | 60 + crates/ir/src/analysis/dominance.rs | 19 + crates/ir/src/analysis/evm_bytecode.rs | 373 +++ crates/ir/src/analysis/mod.rs | 31 + crates/ir/src/analysis/tail_edges.rs | 10 + crates/ir/src/analysis/types.rs | 42 + crates/ir/src/cfg.rs | 291 +- crates/ir/src/instruction.rs | 339 +-- crates/ir/src/lib.rs | 2 + crates/ir/src/pass/dead_code.rs | 15 + crates/ir/src/pass/lift.rs | 19 + crates/ir/src/pass/mod.rs | 8 + crates/ir/src/symbol.rs | 217 +- crates/lld-sys/build.rs | 28 +- crates/lld-sys/src/linker.cpp | 4 +- crates/polkavm/src/lib.rs | 14 - crates/target-polkavm/Cargo.toml | 18 + crates/target-polkavm/polkavm_guest.bc | Bin 0 -> 36020 bytes crates/target-polkavm/src/environment.rs | 77 + crates/target-polkavm/src/lib.rs | 13 + crates/target-polkavm/src/linker.rs | 86 + crates/target-polkavm/src/target.rs | 34 + erc20_paris.yul | 2672 +++++++++++++++++ testdata/empty.bin | 0 testdata/empty_contract_payable_initcode.bin | 1 + testdata/{erc20_old.bin => erc20_paris.bin} | 0 testdata/fibonacci.evm | 1 - testdata/immutable.bin | 1 + ...584f83f26aF4eDDA9CBe8C730bc87C364b28fe.bin | 1 + tmp | 3 + 48 files changed, 4399 insertions(+), 603 deletions(-) rename crates/{polkavm => codegen}/Cargo.toml (51%) create mode 100644 crates/codegen/src/lib.rs create mode 100644 crates/codegen/src/module.rs create mode 100644 crates/codegen/src/program.rs rename crates/{environment => compilation-target}/Cargo.toml (70%) create mode 100644 crates/compilation-target/src/environment.rs create mode 100644 crates/compilation-target/src/lib.rs create mode 100644 crates/compilation-target/src/target.rs delete mode 100644 crates/environment/src/lib.rs create mode 100644 crates/ir/src/analysis/control_flow.rs create mode 100644 crates/ir/src/analysis/dominance.rs create mode 100644 crates/ir/src/analysis/evm_bytecode.rs create mode 100644 crates/ir/src/analysis/mod.rs create mode 100644 crates/ir/src/analysis/tail_edges.rs create mode 100644 crates/ir/src/analysis/types.rs create mode 100644 crates/ir/src/pass/dead_code.rs create mode 100644 crates/ir/src/pass/lift.rs create mode 100644 crates/ir/src/pass/mod.rs delete mode 100644 crates/polkavm/src/lib.rs create mode 100644 crates/target-polkavm/Cargo.toml create mode 100644 crates/target-polkavm/polkavm_guest.bc create mode 100644 crates/target-polkavm/src/environment.rs create mode 100644 crates/target-polkavm/src/lib.rs create mode 100644 crates/target-polkavm/src/linker.rs create mode 100644 crates/target-polkavm/src/target.rs create mode 100644 erc20_paris.yul create mode 100644 testdata/empty.bin create mode 100644 testdata/empty_contract_payable_initcode.bin rename testdata/{erc20_old.bin => erc20_paris.bin} (100%) delete mode 100644 testdata/fibonacci.evm create mode 100644 testdata/immutable.bin create mode 100644 testdata/mimc_83584f83f26aF4eDDA9CBe8C730bc87C364b28fe.bin create mode 100644 tmp diff --git a/.gitignore b/.gitignore index 507684b..f68c749 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target *.dot +.vscode/ diff --git a/Cargo.lock b/Cargo.lock index 4a35a17..5b89db9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,14 +3,22 @@ version = 3 [[package]] -name = "alloy-rlp" -version = "0.3.3" +name = "aho-corasick" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac" dependencies = [ "arrayvec", "bytes", - "smol_str", ] [[package]] @@ -30,9 +38,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "arc-swap" @@ -273,7 +281,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -300,10 +308,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "compiler-builtins" -version = "0.1.0" - [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -379,6 +383,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "evmil" version = "0.4.5" @@ -392,6 +406,18 @@ dependencies = [ "ruint", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "fastrlp" version = "0.3.1" @@ -445,15 +471,25 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", "wasi", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +dependencies = [ + "fallible-iterator", + "stable_deref_trait", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -489,9 +525,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -550,6 +586,31 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "inkwell" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4fcb4a4fa0b8f7b4178e24e6317d6f8b95ab500d8e6e1bd4283b6860e369c1" +dependencies = [ + "either", + "inkwell_internals", + "libc", + "llvm-sys", + "once_cell", + "parking_lot", +] + +[[package]] +name = "inkwell_internals" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b185e7d068d6820411502efa14d8fbf010750485399402156b72dd2a548ef8e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "itertools" version = "0.10.5" @@ -582,9 +643,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.150" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "libm" @@ -598,6 +659,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + [[package]] name = "lld-sys" version = "0.1.0" @@ -606,6 +673,19 @@ dependencies = [ "libc", ] +[[package]] +name = "llvm-sys" +version = "160.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f9888529887dfda6c59e20f0e0727b17e826cd54ae1ddf0d4c83850fa23b69" +dependencies = [ + "cc", + "lazy_static", + "libc", + "regex", + "semver 1.0.21", +] + [[package]] name = "lock_api" version = "0.4.11" @@ -659,9 +739,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "num-bigint" @@ -694,6 +774,15 @@ dependencies = [ "libm", ] +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -761,7 +850,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -772,9 +861,9 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "pest" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06" dependencies = [ "memchr", "thiserror", @@ -791,6 +880,24 @@ dependencies = [ "indexmap 2.1.0", ] +[[package]] +name = "polkavm-common" +version = "0.3.0" +source = "git+https://github.com/koute/polkavm.git?rev=3552524a248a025de8e608394fcf9eb7c528eb11#3552524a248a025de8e608394fcf9eb7c528eb11" + +[[package]] +name = "polkavm-linker" +version = "0.3.0" +source = "git+https://github.com/koute/polkavm.git?rev=3552524a248a025de8e608394fcf9eb7c528eb11#3552524a248a025de8e608394fcf9eb7c528eb11" +dependencies = [ + "gimli", + "hashbrown 0.14.3", + "log", + "object", + "polkavm-common", + "rustc-demangle", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -844,9 +951,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -869,9 +976,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -930,24 +1037,65 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "revive-builtins" +version = "0.1.0" + [[package]] name = "revive-cli" version = "0.1.0" dependencies = [ "evmil", "hex", + "revive-codegen", + "revive-ir", + "revive-target-polkavm", +] + +[[package]] +name = "revive-codegen" +version = "0.1.0" +dependencies = [ + "inkwell", + "revive-compilation-target", "revive-ir", ] [[package]] -name = "revive-environment" +name = "revive-compilation-target" version = "0.1.0" +dependencies = [ + "inkwell", +] [[package]] name = "revive-ir" @@ -957,11 +1105,23 @@ dependencies = [ "indexmap 2.1.0", "petgraph", "primitive-types", + "revive-compilation-target", ] [[package]] -name = "revive-polkavm" +name = "revive-target-polkavm" version = "0.1.0" +dependencies = [ + "inkwell", + "libc", + "lld-sys", + "polkavm-common", + "polkavm-linker", + "revive-builtins", + "revive-codegen", + "revive-compilation-target", + "tempfile", +] [[package]] name = "rlp" @@ -1003,6 +1163,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -1024,14 +1190,27 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.20", + "semver 1.0.21", +] + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", ] [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "scopeguard" @@ -1050,9 +1229,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "semver-parser" @@ -1065,9 +1244,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" dependencies = [ "serde_derive", ] @@ -1084,20 +1263,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.195" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" dependencies = [ "itoa", "ryu", @@ -1123,13 +1302,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] -name = "smol_str" -version = "0.2.0" +name = "stable_deref_trait" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" -dependencies = [ - "serde", -] +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "static_assertions" @@ -1156,9 +1332,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -1172,10 +1348,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] -name = "termcolor" -version = "1.4.0" +name = "tempfile" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -1188,22 +1377,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] [[package]] @@ -1326,7 +1515,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -1348,7 +1537,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1392,11 +1581,20 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.51.1" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -1405,13 +1603,28 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -1420,36 +1633,72 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -1457,10 +1706,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "winnow" -version = "0.5.26" +name = "windows_x86_64_msvc" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67b5f0a4e7a27a64c651977932b9dc5667ca7fc31ac44b03ed37a0cf42fdfff" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa" dependencies = [ "memchr", ] @@ -1500,5 +1755,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.48", ] diff --git a/Cargo.toml b/Cargo.toml index bf27474..aa3128c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,6 @@ indexmap = "2.1.0" inkwell = { version = "0.2.0", features = ["target-riscv", "no-libffi-linking", "llvm16-0"] } cc = "1.0" libc = "0.2" +tempfile = "3.8" +polkavm-common = { git = "https://github.com/koute/polkavm.git", rev = "3552524a248a025de8e608394fcf9eb7c528eb11" } +polkavm-linker = { git = "https://github.com/koute/polkavm.git", rev = "3552524a248a025de8e608394fcf9eb7c528eb11" } diff --git a/crates/builtins/Cargo.toml b/crates/builtins/Cargo.toml index 605b68e..c4f1223 100644 --- a/crates/builtins/Cargo.toml +++ b/crates/builtins/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "compiler-builtins" +name = "revive-builtins" version = "0.1.0" edition = "2021" build = "build.rs" diff --git a/crates/builtins/build.rs b/crates/builtins/build.rs index d05bfe4..e16d4eb 100644 --- a/crates/builtins/build.rs +++ b/crates/builtins/build.rs @@ -16,7 +16,7 @@ fn main() { let lib_path = std::path::PathBuf::from(llvm_lib_dir.trim()) .join("linux") .join(lib); - let archive = fs::read(lib_path).expect("clang builtins for riscv32 not fonud"); + let archive = fs::read(lib_path).expect("clang builtins for riscv32 not found"); let out_dir = env::var_os("OUT_DIR").expect("has OUT_DIR"); let archive_path = Path::new(&out_dir).join(lib); diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 24830a6..efe31d6 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -8,4 +8,7 @@ edition = "2021" [dependencies] hex = { workspace = true } evmil = { workspace = true } -revive-ir = { path = "../ir" } \ No newline at end of file + +revive-ir = { path = "../ir" } +revive-codegen = { path = "../codegen" } +revive-target-polkavm = { path = "../target-polkavm" } \ No newline at end of file diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index a1af99f..7322864 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -1,10 +1,21 @@ use evmil::bytecode::Disassemble; -use revive_ir::cfg::{BasicBlockFormatOption, Program}; +use revive_ir::cfg::BasicBlockFormatOption; +use revive_target_polkavm::PolkaVm; fn main() { let hexcode = std::fs::read_to_string(std::env::args().nth(1).unwrap()).unwrap(); let bytecode = hex::decode(hexcode.trim()).unwrap(); let instructions = bytecode.disassemble(); - Program::new(instructions).dot(BasicBlockFormatOption::ByteCode); + let mut ir = revive_ir::cfg::Program::new(&instructions); + ir.optimize(); + ir.dot(BasicBlockFormatOption::Ir); + + let target = PolkaVm::default(); + let program = revive_codegen::program::Program::new(&target).unwrap(); + program.emit(ir); + + let artifact = program.compile_and_link(); + + std::fs::write("/tmp/out.pvm", artifact).unwrap(); } diff --git a/crates/polkavm/Cargo.toml b/crates/codegen/Cargo.toml similarity index 51% rename from crates/polkavm/Cargo.toml rename to crates/codegen/Cargo.toml index 185470b..c42f91f 100644 --- a/crates/polkavm/Cargo.toml +++ b/crates/codegen/Cargo.toml @@ -1,8 +1,12 @@ [package] -name = "revive-polkavm" +name = "revive-codegen" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +inkwell = { workspace = true } + +revive-compilation-target = { path = "../compilation-target" } +revive-ir = { path = "../ir" } \ No newline at end of file diff --git a/crates/codegen/src/lib.rs b/crates/codegen/src/lib.rs new file mode 100644 index 0000000..29146a4 --- /dev/null +++ b/crates/codegen/src/lib.rs @@ -0,0 +1,2 @@ +mod module; +pub mod program; diff --git a/crates/codegen/src/module.rs b/crates/codegen/src/module.rs new file mode 100644 index 0000000..f9a2460 --- /dev/null +++ b/crates/codegen/src/module.rs @@ -0,0 +1,37 @@ +use inkwell::{ + module::Module, + support::LLVMString, + targets::{RelocMode, TargetTriple}, +}; +use revive_compilation_target::target::Target; + +pub(crate) fn create<'ctx, T>(target: &'ctx T) -> Result, LLVMString> +where + T: Target<'ctx>, +{ + let module = target.context().create_module("contract"); + + module.set_triple(&TargetTriple::create(::TARGET_TRIPLE)); + module.set_source_file_name("contract.bin"); + + set_flags(target, &module); + + for lib in target.libraries() { + module.link_in_module(lib)?; + } + + Ok(module) +} + +fn set_flags<'ctx, T>(target: &'ctx T, module: &Module<'ctx>) +where + T: Target<'ctx>, +{ + if let RelocMode::PIC = ::RELOC_MODE { + module.add_basic_value_flag( + "PIE Level", + inkwell::module::FlagBehavior::Override, + target.context().i32_type().const_int(2, false), + ); + } +} diff --git a/crates/codegen/src/program.rs b/crates/codegen/src/program.rs new file mode 100644 index 0000000..5574545 --- /dev/null +++ b/crates/codegen/src/program.rs @@ -0,0 +1,93 @@ +use inkwell::{ + builder::Builder, + module::{Linkage, Module}, + support::LLVMString, + targets::{FileType, TargetTriple}, + values::{FunctionValue, GlobalValue}, + AddressSpace, +}; + +use revive_compilation_target::environment::Environment; +use revive_compilation_target::target::Target; + +use crate::module; + +pub struct Program<'ctx, T> { + pub module: Module<'ctx>, + pub builder: Builder<'ctx>, + pub calldata: GlobalValue<'ctx>, + pub returndata: GlobalValue<'ctx>, + pub target: &'ctx T, + pub start: FunctionValue<'ctx>, +} + +impl<'ctx, T> Program<'ctx, T> +where + T: Target<'ctx> + Environment<'ctx>, +{ + pub fn new(target: &'ctx T) -> Result { + T::initialize_llvm(); + + let context = target.context(); + + let module = module::create(target)?; + let builder = context.create_builder(); + let address_space = Some(AddressSpace::default()); + + let calldata_type = context.i8_type().array_type(T::CALLDATA_SIZE); + let calldata = module.add_global(calldata_type, address_space, "calldata"); + + let returndata_type = context.i8_type().array_type(T::RETURNDATA_SIZE); + let returndata = module.add_global(returndata_type, address_space, "returndata"); + + let start_fn_type = target.context().void_type().fn_type(&[], false); + let start = module.add_function("start", start_fn_type, Some(Linkage::Internal)); + + Ok(Self { + module, + builder, + calldata, + returndata, + target, + start, + }) + } + + pub fn emit(&self, program: revive_ir::cfg::Program) { + self.emit_start(); + } + + pub fn compile_and_link(&self) -> Vec { + inkwell::targets::Target::from_name(T::TARGET_NAME) + .expect("target name should be valid") + .create_target_machine( + &TargetTriple::create(T::TARGET_TRIPLE), + T::CPU, + T::TARGET_FEATURES, + self.target.optimization_level(), + T::RELOC_MODE, + T::CODE_MODEL, + ) + .expect("target configuration should be valid") + .write_to_memory_buffer(&self.module, FileType::Object) + .map(|out| self.target.link(out.as_slice())) + .expect("linker should succeed") + .to_vec() + } + + fn emit_start(&self) { + let start = self.start; + let block = self + .start + .get_last_basic_block() + .unwrap_or_else(|| self.target.context().append_basic_block(start, "entry")); + + self.builder.position_at_end(block); + self.builder.build_return(None); + + let env_start = self.target.call_start(&self.builder, self.start); + self.module + .link_in_module(env_start) + .expect("entrypoint module should be linkable"); + } +} diff --git a/crates/environment/Cargo.toml b/crates/compilation-target/Cargo.toml similarity index 70% rename from crates/environment/Cargo.toml rename to crates/compilation-target/Cargo.toml index 5fbb07e..cd0b35d 100644 --- a/crates/environment/Cargo.toml +++ b/crates/compilation-target/Cargo.toml @@ -1,8 +1,9 @@ [package] -name = "revive-environment" +name = "revive-compilation-target" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +inkwell = { workspace = true } diff --git a/crates/compilation-target/src/environment.rs b/crates/compilation-target/src/environment.rs new file mode 100644 index 0000000..aa405b7 --- /dev/null +++ b/crates/compilation-target/src/environment.rs @@ -0,0 +1,15 @@ +use inkwell::{builder::Builder, module::Module, values::FunctionValue}; + +/// [Environment] describes EVM runtime functionality. +pub trait Environment<'ctx> { + const STACK_SIZE: u32 = 1024 * 32; + const CALLDATA_SIZE: u32 = 0x10000; + const RETURNDATA_SIZE: u32 = 0x10000; + const MEMORY_SIZE: u32 = 0x100000; + + /// Build a module containing all required runtime exports and imports. + /// + /// The `start` function is the entrypoint to the contract logic. + /// The returned `Module` is expected to call `start` somewhere. + fn call_start(&'ctx self, builder: &Builder<'ctx>, start: FunctionValue<'ctx>) -> Module<'ctx>; +} diff --git a/crates/compilation-target/src/lib.rs b/crates/compilation-target/src/lib.rs new file mode 100644 index 0000000..d313b7d --- /dev/null +++ b/crates/compilation-target/src/lib.rs @@ -0,0 +1,2 @@ +pub mod environment; +pub mod target; diff --git a/crates/compilation-target/src/target.rs b/crates/compilation-target/src/target.rs new file mode 100644 index 0000000..69b4414 --- /dev/null +++ b/crates/compilation-target/src/target.rs @@ -0,0 +1,27 @@ +use inkwell::{ + context::Context, + module::Module, + targets::{CodeModel, RelocMode}, + OptimizationLevel, +}; + +pub trait Target<'ctx> { + const TARGET_NAME: &'ctx str; + const TARGET_TRIPLE: &'ctx str; + const TARGET_FEATURES: &'ctx str; + const CPU: &'ctx str; + const RELOC_MODE: RelocMode = RelocMode::Default; + const CODE_MODEL: CodeModel = CodeModel::Default; + + fn initialize_llvm() { + inkwell::targets::Target::initialize_riscv(&Default::default()); + } + + fn context(&self) -> &Context; + + fn libraries(&'ctx self) -> Vec>; + + fn link(&self, blob: &[u8]) -> Vec; + + fn optimization_level(&self) -> OptimizationLevel; +} diff --git a/crates/environment/src/lib.rs b/crates/environment/src/lib.rs deleted file mode 100644 index 8b13789..0000000 --- a/crates/environment/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/ir/Cargo.toml b/crates/ir/Cargo.toml index 924b0c1..6179feb 100644 --- a/crates/ir/Cargo.toml +++ b/crates/ir/Cargo.toml @@ -9,4 +9,6 @@ edition = "2021" evmil = { workspace = true } petgraph = { workspace = true } primitive-types = { workspace = true } -indexmap = { workspace = true } \ No newline at end of file +indexmap = { workspace = true } + +revive-compilation-target = { path = "../compilation-target" } diff --git a/crates/ir/src/address.rs b/crates/ir/src/address.rs index 61dee2e..54dc223 100644 --- a/crates/ir/src/address.rs +++ b/crates/ir/src/address.rs @@ -30,13 +30,13 @@ impl Address { #[derive(Clone, Copy)] pub enum Type { - Int { size: u8 }, + Int { size: u16 }, Bytes { size: u8 }, Bool, } impl Type { - pub fn int(size: u8) -> Self { + pub fn int(size: u16) -> Self { Self::Int { size } } @@ -47,7 +47,7 @@ impl Type { impl Default for Type { fn default() -> Self { - Type::Int { size: 32 } + Type::Bytes { size: 32 } } } diff --git a/crates/ir/src/analysis/control_flow.rs b/crates/ir/src/analysis/control_flow.rs new file mode 100644 index 0000000..d3a463d --- /dev/null +++ b/crates/ir/src/analysis/control_flow.rs @@ -0,0 +1,60 @@ +use indexmap::{IndexMap, IndexSet}; +use petgraph::prelude::*; + +use crate::{ + analysis::BlockAnalysis, + cfg::{Branch, Program}, + instruction::Instruction, + symbol::Kind, +}; + +/// Remove basic blocks not reachable from the start node. +#[derive(Default)] +pub struct ReachableCode(pub IndexSet); + +impl BlockAnalysis for ReachableCode { + fn analyze_block(&mut self, node: NodeIndex, _program: &mut Program) { + self.0.insert(node); + } + + fn apply_results(&mut self, program: &mut Program) { + program.cfg.graph.retain_nodes(|_, i| self.0.contains(&i)); + } +} + +/// Remove edges to the jump table if the jump target is statically known. +#[derive(Default)] +pub struct StaticJumps(IndexMap); + +impl BlockAnalysis for StaticJumps { + fn analyze_block(&mut self, node: NodeIndex, program: &mut Program) { + for edge in program.cfg.graph.edges(node) { + if *edge.weight() == Branch::Static { + continue; + } + + if let Some(Instruction::ConditionalBranch { target, .. }) + | Some(Instruction::UncoditionalBranch { target }) = + program.cfg.graph[node].instructions.last() + { + let Kind::Constant(bytecode_offset) = target.symbol().kind else { + continue; + }; + + let destination = program + .jump_targets + .get(&bytecode_offset.as_usize()) + .unwrap_or(&program.cfg.invalid_jump); + + self.0.insert(edge.id(), (node, *destination)); + } + } + } + + fn apply_results(&mut self, program: &mut Program) { + for (edge, (a, b)) in &self.0 { + program.cfg.graph.remove_edge(*edge); + program.cfg.graph.add_edge(*a, *b, Branch::Static); + } + } +} diff --git a/crates/ir/src/analysis/dominance.rs b/crates/ir/src/analysis/dominance.rs new file mode 100644 index 0000000..023f39c --- /dev/null +++ b/crates/ir/src/analysis/dominance.rs @@ -0,0 +1,19 @@ +use crate::{cfg::Program, instruction::Instruction, symbol::Type, POINTER_SIZE}; +use petgraph::prelude::*; + +use super::BlockAnalysis; + +#[derive(Default)] +pub struct Unstack; + +impl BlockAnalysis for Unstack { + fn analyze_block(&mut self, node: NodeIndex, program: &mut Program) { + for instruction in &program.cfg.graph[node].instructions { + match instruction { + _ => {} + } + } + } + + fn apply_results(&mut self, _program: &mut Program) {} +} diff --git a/crates/ir/src/analysis/evm_bytecode.rs b/crates/ir/src/analysis/evm_bytecode.rs new file mode 100644 index 0000000..2f53725 --- /dev/null +++ b/crates/ir/src/analysis/evm_bytecode.rs @@ -0,0 +1,373 @@ +use indexmap::{IndexMap, IndexSet}; +use petgraph::prelude::*; + +use crate::{ + analysis::BlockAnalysis, + cfg::{Program, StackInfo}, + instruction::{Instruction, Operator}, + symbol::{Global, Kind, Symbol, SymbolBuilder, SymbolRef, SymbolTable}, +}; + +#[derive(Default)] +pub struct IrBuilder; + +impl BlockAnalysis for IrBuilder { + fn analyze_block(&mut self, node: NodeIndex, program: &mut Program) { + let mut builder = BlockBuilder::new(node, &mut program.symbol_table); + + for opcode in &program.evm_instructions[program.cfg.graph[node].opcodes.to_owned()] { + builder.translate(&opcode.instruction); + } + + let (instructions, stack_info) = builder.done(); + + program.cfg.graph[node].instructions = instructions; + program.cfg.graph[node].stack_info = stack_info; + } + + fn apply_results(&mut self, _program: &mut Program) {} +} + +pub struct BlockBuilder<'tbl> { + state: State<'tbl>, + instructions: Vec, +} + +impl<'tbl> BlockBuilder<'tbl> { + fn new(node: NodeIndex, symbol_table: &'tbl mut SymbolTable) -> Self { + Self { + state: State::new(node, symbol_table), + instructions: Default::default(), + } + } + + fn done(self) -> (Vec, StackInfo) { + let stack_info = StackInfo { + arguments: self.state.borrows, + generates: self.state.stack, + height: self.state.height, + }; + + assert_eq!( + stack_info.arguments as i32 + stack_info.height, + stack_info.generates.len() as i32, + "local stack elements must equal stack arguments taken + local height" + ); + + (self.instructions, stack_info) + } + + fn translate(&mut self, opcode: &evmil::bytecode::Instruction) { + use evmil::bytecode::Instruction::*; + self.instructions.extend(match opcode { + JUMPDEST => Vec::new(), + + PUSH(bytes) => { + self.state.push(Symbol::builder().constant(bytes)); + + Vec::new() + } + + POP => { + self.state.pop(); + + Vec::new() + } + + SWAP(n) => self.state.swap(*n as usize), + + DUP(n) => vec![Instruction::Copy { + y: self.state.nth(*n as usize), + x: self.state.push(Symbol::builder().variable()), + }], + + ADD => vec![Instruction::BinaryAssign { + y: self.state.pop(), + z: self.state.pop(), + x: self.state.push(Symbol::builder().variable()), + operator: Operator::Add, + }], + + SUB => vec![Instruction::BinaryAssign { + y: self.state.pop(), + z: self.state.pop(), + x: self.state.push(Symbol::builder().variable()), + operator: Operator::Sub, + }], + + MSTORE => vec![Instruction::IndexedAssign { + x: self.state.symbol_table.global(Global::Memory), + index: self.state.pop(), + y: self.state.pop(), + }], + + MLOAD => vec![Instruction::IndexedCopy { + index: self.state.pop(), + x: self.state.push(Symbol::builder().variable()), + y: self.state.symbol_table.global(Global::Memory), + }], + + JUMP => vec![Instruction::UncoditionalBranch { + target: self.state.pop(), + }], + + JUMPI => vec![Instruction::ConditionalBranch { + target: self.state.pop(), + condition: self.state.pop(), + }], + + CALLDATACOPY => vec![Instruction::Procedure { + symbol: Global::CallDataCopy, + parameters: vec![self.state.pop(), self.state.pop(), self.state.pop()], + }], + + CALLDATALOAD => vec![Instruction::IndexedCopy { + index: self.state.pop(), + x: self.state.push(Symbol::builder().variable()), + y: self.state.symbol_table.global(Global::CallData), + }], + + RETURN => vec![Instruction::Procedure { + symbol: Global::Return, + parameters: vec![self.state.pop(), self.state.pop()], + }], + + GT => vec![Instruction::BinaryAssign { + y: self.state.pop(), + z: self.state.pop(), + x: self.state.push(Symbol::builder().variable()), + operator: Operator::GreaterThan, + }], + + LT => vec![Instruction::BinaryAssign { + y: self.state.pop(), + z: self.state.pop(), + x: self.state.push(Symbol::builder().variable()), + operator: Operator::LessThan, + }], + + EQ => vec![Instruction::BinaryAssign { + y: self.state.pop(), + z: self.state.pop(), + x: self.state.push(Symbol::builder().variable()), + operator: Operator::Equal, + }], + + ISZERO => vec![Instruction::UnaryAssign { + y: self.state.pop(), + x: self.state.push(Symbol::builder().variable()), + operator: Operator::IsZero, + }], + + _ => { + eprintln!("unimplement instruction: {opcode}"); + Vec::new() + } + }) + } +} + +struct State<'tbl> { + node: NodeIndex, + symbol_table: &'tbl mut SymbolTable, + stack: Vec, + /// Every pop on an empty stack was counts as an additional argument. + borrows: usize, + /// Caches the arguments the block borrows from the stack. + arguments: IndexMap, + /// Tracks the relative stack height: + /// - Pushes increase the height by one + /// - Pops decrease the height by one + height: i32, +} + +impl<'tbl> State<'tbl> { + fn new(node: NodeIndex, symbol_table: &'tbl mut SymbolTable) -> Self { + Self { + node, + symbol_table, + stack: Default::default(), + borrows: Default::default(), + arguments: Default::default(), + height: Default::default(), + } + } + + fn pop(&mut self) -> SymbolRef { + self.height -= 1; + self.stack.pop().unwrap_or_else(|| { + self.borrows += 1; + self.nth(0) + }) + } + + fn push(&mut self, builder: SymbolBuilder<(), Kind>) -> SymbolRef { + let symbol = builder.temporary().done(); + let symbol = self.symbol_table.insert(self.node, symbol); + self.stack.push(symbol.clone()); + self.height += 1; + + symbol + } + + fn swap(&mut self, n: usize) -> Vec { + // For free if both elements are local to the basic block + let top = self.stack.len().saturating_sub(1); + if n <= top { + self.stack.swap(top - n, top); + return Vec::new(); + } + + let tmp = self.symbol_table.temporary(self.node); + let a = self.nth(0); + let b = self.nth(n); + + vec![ + Instruction::Copy { + x: tmp.clone(), + y: a.clone(), + }, + Instruction::Copy { x: a, y: b.clone() }, + Instruction::Copy { x: b, y: tmp }, + ] + } + + fn nth(&mut self, n: usize) -> SymbolRef { + self.stack + .iter() + .rev() + .nth(n) + .or_else(|| self.arguments.get(&(self.slot(n) as usize))) + .cloned() + .unwrap_or_else(|| { + let builder = Symbol::builder().stack(self.slot(n)).variable(); + let symbol = self.symbol_table.insert(self.node, builder.done()); + self.arguments.insert(self.slot(n) as usize, symbol.clone()); + symbol + }) + } + + fn slot(&self, n: usize) -> i32 { + n as i32 - (self.stack.len() as i32 - self.borrows as i32) + } +} + +#[cfg(test)] +mod tests { + use super::{BlockBuilder, State}; + use crate::{ + cfg::StackInfo, + instruction::Instruction, + symbol::{Symbol, SymbolTable}, + }; + use evmil::bytecode::Instruction::*; + + fn translate<'tbl>(code: &[evmil::bytecode::Instruction]) -> (Vec, StackInfo) { + code.iter() + .fold( + BlockBuilder::new(Default::default(), &mut SymbolTable::default()), + |mut builder, instruction| { + builder.translate(instruction); + builder + }, + ) + .done() + } + + #[test] + fn stack_slot_works() { + let mut symbol_table = SymbolTable::default(); + let mut state = State::new(Default::default(), &mut symbol_table); + + state.push(Symbol::builder().variable()); + assert_eq!(state.slot(0), -1); + assert_eq!(state.slot(1), 0); + assert_eq!(state.slot(2), 1); + + state.pop(); + state.pop(); + assert_eq!(state.slot(0), 1); + assert_eq!(state.slot(1), 2); + assert_eq!(state.slot(2), 3); + + state.push(Symbol::builder().variable()); + state.push(Symbol::builder().variable()); + assert_eq!(state.slot(0), -1); + assert_eq!(state.slot(1), 0); + assert_eq!(state.slot(2), 1); + } + + #[test] + fn push_works() { + let state = translate(&[PUSH(vec![1])]).1; + + assert_eq!(state.height, 1); + assert_eq!(state.arguments, 0); + assert_eq!(state.generates.len(), 1); + } + + #[test] + fn add_works() { + let state = translate(&[ADD]).1; + + assert_eq!(state.height, -1); + assert_eq!(state.arguments, 2); + assert_eq!(state.generates.len(), 1); + } + + #[test] + fn dup_works() { + let state = translate(&[DUP(4)]).1; + + assert_eq!(state.height, 1); + assert_eq!(state.arguments, 0); + assert_eq!(state.generates.len(), 1); + } + + #[test] + fn swap_works() { + let state = translate(&[SWAP(4)]).1; + + assert_eq!(state.height, 0); + assert_eq!(state.arguments, 0); + assert_eq!(state.generates.len(), 0); + } + + #[test] + fn jump() { + let state = translate(&[JUMP]).1; + + assert_eq!(state.height, -1); + assert_eq!(state.arguments, 1); + assert_eq!(state.generates.len(), 0); + } + + #[test] + fn pop5_push2() { + let state = translate(&[POP, POP, POP, POP, POP, PUSH(vec![1]), PUSH(vec![1])]).1; + + assert_eq!(state.height, -3); + assert_eq!(state.arguments, 5); + assert_eq!(state.generates.len(), 2); + } + + #[test] + fn fibonacci_loop_body() { + let state = translate(&[ + PUSH(vec![1]), + ADD, + SWAP(2), + DUP(1), + SWAP(4), + ADD, + SWAP(2), + PUSH(vec![10]), + JUMP, + ]) + .1; + + assert_eq!(state.height, 0); + assert_eq!(state.arguments, 1); + assert_eq!(state.generates.len(), 1); + } +} diff --git a/crates/ir/src/analysis/mod.rs b/crates/ir/src/analysis/mod.rs new file mode 100644 index 0000000..2a56c32 --- /dev/null +++ b/crates/ir/src/analysis/mod.rs @@ -0,0 +1,31 @@ +use petgraph::prelude::*; + +use crate::cfg::Program; + +pub mod control_flow; +pub mod dominance; +pub mod evm_bytecode; +pub mod types; + +/// The analyzer visits each basic block using DFS. +pub trait BlockAnalysis: Default { + fn analyze_block(&mut self, node: NodeIndex, program: &mut Program); + + fn apply_results(&mut self, program: &mut Program); +} + +pub fn analyze(program: &mut Program) -> Pass +where + Pass: BlockAnalysis, +{ + let mut dfs = Dfs::new(&program.cfg.graph, program.cfg.start); + let mut pass = Pass::default(); + + while let Some(node) = dfs.next(&program.cfg.graph) { + pass.analyze_block(node, program); + } + + pass.apply_results(program); + + pass +} diff --git a/crates/ir/src/analysis/tail_edges.rs b/crates/ir/src/analysis/tail_edges.rs new file mode 100644 index 0000000..55170ac --- /dev/null +++ b/crates/ir/src/analysis/tail_edges.rs @@ -0,0 +1,10 @@ +use indexmap::IndexMap; +use petgraph::prelude::*; + +use crate::{ + cfg::{Branch, Program}, + instruction::Instruction, + symbol::Kind, +}; + +use super::BlockAnalysis; diff --git a/crates/ir/src/analysis/types.rs b/crates/ir/src/analysis/types.rs new file mode 100644 index 0000000..af00cd1 --- /dev/null +++ b/crates/ir/src/analysis/types.rs @@ -0,0 +1,42 @@ +use crate::{cfg::Program, instruction::Instruction, symbol::Type, POINTER_SIZE}; +use petgraph::prelude::*; + +use super::BlockAnalysis; + +#[derive(Default)] +pub struct TypePropagation; + +impl BlockAnalysis for TypePropagation { + fn analyze_block(&mut self, node: NodeIndex, program: &mut Program) { + for instruction in &program.cfg.graph[node].instructions { + match instruction { + Instruction::ConditionalBranch { condition, target } => { + condition.replace_type(Type::Bool); + target.replace_type(Type::Int(POINTER_SIZE)); + } + + Instruction::UncoditionalBranch { target } => { + target.replace_type(Type::Int(POINTER_SIZE)); + } + + Instruction::BinaryAssign { x, y, z, .. } => { + y.replace_type(x.symbol().type_hint); + z.replace_type(x.symbol().type_hint); + } + + Instruction::Copy { x, y } | Instruction::UnaryAssign { x, y, .. } => { + x.replace_type(y.symbol().type_hint); + } + + Instruction::IndexedCopy { index, .. } + | Instruction::IndexedAssign { index, .. } => { + index.replace_type(Type::Int(POINTER_SIZE)) + } + + _ => {} + } + } + } + + fn apply_results(&mut self, _program: &mut Program) {} +} diff --git a/crates/ir/src/cfg.rs b/crates/ir/src/cfg.rs index 742b7dc..314106d 100644 --- a/crates/ir/src/cfg.rs +++ b/crates/ir/src/cfg.rs @@ -1,48 +1,74 @@ use std::fmt::Write; use std::ops::Range; -use evmil::bytecode; -use petgraph::{ - dot::{Config, Dot}, - graph::DiGraph, - stable_graph::NodeIndex, -}; +use indexmap::IndexMap; +use petgraph::dot::{Config, Dot}; +use petgraph::prelude::*; -use crate::{ - instruction::{self, Instruction}, - symbol::SymbolTable, -}; +use crate::pass::dead_code::DeadCodeElimination; +use crate::pass::lift::BytecodeLifter; +use crate::pass::Pass; +use crate::symbol::SymbolRef; +use crate::{instruction::Instruction, symbol::SymbolTable}; + +pub struct Cfg { + pub graph: StableDiGraph, + pub start: NodeIndex, + pub jump_table: NodeIndex, + pub terminator: NodeIndex, + pub invalid_jump: NodeIndex, +} + +#[derive(Debug, PartialEq)] +pub enum Branch { + Static, + Dynamic, +} + +impl Default for Cfg { + fn default() -> Self { + let mut graph = StableDiGraph::new(); + + Self { + start: graph.add_node(Default::default()), + jump_table: graph.add_node(Default::default()), + terminator: graph.add_node(Default::default()), + invalid_jump: graph.add_node(Default::default()), + graph, + } + } +} #[derive(Clone, Debug)] pub struct EvmInstruction { pub bytecode_offset: usize, - pub instruction: bytecode::Instruction, + pub instruction: evmil::bytecode::Instruction, } #[derive(Debug, Default)] pub struct BasicBlock { - pub entry: Option, pub opcodes: Range, pub instructions: Vec, + pub stack_info: StackInfo, } -#[derive(Clone, Copy, Default)] -pub enum BasicBlockFormatOption { - ByteCode, - Ir, - #[default] - None, +#[derive(Debug, Default)] +pub struct StackInfo { + pub arguments: usize, + pub generates: Vec, + pub height: i32, } impl BasicBlock { + fn linear_at(start: usize) -> Self { + Self { + opcodes: start..start + 1, + ..Default::default() + } + } + fn format(&self, evm_bytecode: &[EvmInstruction], options: BasicBlockFormatOption) -> String { - let offset = evm_bytecode[self.opcodes.start].bytecode_offset; - let start = if let Some(Entry::Start) = self.entry { - "Start\n".to_string() - } else { - String::new() - }; - let instructions = match options { + match options { BasicBlockFormatOption::ByteCode => evm_bytecode[self.opcodes.start..self.opcodes.end] .iter() .fold(String::new(), |mut acc, opcode| { @@ -58,164 +84,155 @@ impl BasicBlock { }) } _ => String::new(), - }; - - format!("{start}Offset: 0x{offset:02x}\n---\n{instructions}") + } } } -#[derive(Clone, Debug)] -pub enum Entry { - Start, - Jumpdest(NodeIndex), - Else(NodeIndex), -} - -#[derive(Debug)] -pub enum Jump { - Direct, - Indirect, +#[derive(Clone, Copy, Default)] +pub enum BasicBlockFormatOption { + ByteCode, + Ir, + #[default] + None, } pub struct Program { pub evm_instructions: Vec, - pub cfg: DiGraph, + pub cfg: Cfg, pub symbol_table: SymbolTable, + pub jump_targets: IndexMap, } impl Program { - pub fn new(bytecode: Vec) -> Self { - let mut cfg = DiGraph::new(); - let mut symbol_table = SymbolTable::default(); + /// Create a new [Program] from EVM bytecode. + /// + /// - Dynamic jumps reach the dynamic jump table + /// - `JUMPDEST` and `JUMPI` split up the node + /// - Instructions not returning reach the terminator node + pub fn new(bytecode: &[evmil::bytecode::Instruction]) -> Self { let mut evm_instructions = Vec::with_capacity(bytecode.len()); - - let mut current_block = Some(BasicBlock { - entry: Some(Entry::Start), - ..Default::default() - }); + let mut cfg = Cfg::default(); + let mut jump_targets = IndexMap::default(); let mut bytecode_offset = 0; + let mut node = cfg.graph.add_node(Default::default()); + cfg.graph.add_edge(cfg.start, node, Branch::Static); + cfg.graph + .add_edge(cfg.invalid_jump, cfg.terminator, Branch::Static); + cfg.graph + .add_edge(cfg.jump_table, cfg.invalid_jump, Branch::Dynamic); for (index, opcode) in bytecode.iter().enumerate() { evm_instructions.push(EvmInstruction { bytecode_offset, instruction: opcode.clone(), }); - bytecode_offset += opcode.length(); + cfg.graph[node].opcodes.end = index + 1; - let instructions = instruction::translate(opcode, &mut symbol_table); - - use bytecode::Instruction::*; + use evmil::bytecode::Instruction::*; match opcode { - JUMPDEST => { - // If we are already in a bb, conclude it - let entry = current_block.take().map(|mut node| { - node.opcodes.end = index + 1; - let entry = node.entry.clone(); - let node_index = cfg.add_node(node); + // The preceding instruction did already split up control flow + JUMPDEST + if matches!( + evm_instructions[index.saturating_sub(1)].instruction, + JUMP | JUMPI | RETURN | REVERT | INVALID | STOP | SELFDESTRUCT + ) => + { + cfg.graph.add_edge(cfg.jump_table, node, Branch::Dynamic); - // If the block had an entry, add an edge from the previous block to it - if let Some(Entry::Else(incoming)) | Some(Entry::Jumpdest(incoming)) = entry - { - cfg.add_edge(incoming, node_index, Jump::Direct); - } - node_index - }); - - // JUMPDEST implicitly starts a new bb - current_block = Some(BasicBlock { - entry: entry.map(Entry::Jumpdest), - opcodes: Range { - start: index + 1, - end: index + 1, - }, - ..Default::default() - }); + jump_targets.insert(bytecode_offset, node); } - JUMP | STOP | RETURN | REVERT | INVALID => { - // Conclude this bb; if we are not already in a bb we must create a new one - let mut node = current_block.take().unwrap_or_else(|| BasicBlock { - opcodes: Range { - start: index, - end: index + 1, - }, - ..Default::default() - }); - node.instructions.extend(instructions); - node.opcodes.end = index + 1; + JUMPDEST => { + cfg.graph[node].opcodes.end = index; + let previous_node = node; + node = cfg.graph.add_node(BasicBlock::linear_at(index)); - let entry = node.entry.clone(); - let node_index = cfg.add_node(node); + cfg.graph.add_edge(cfg.jump_table, node, Branch::Dynamic); + cfg.graph.add_edge(previous_node, node, Branch::Static); - // If the block had an entry, add an edge from the previous block to it - if let Some(Entry::Else(incoming)) | Some(Entry::Jumpdest(incoming)) = entry { - cfg.add_edge(incoming, node_index, Jump::Direct); - } + jump_targets.insert(bytecode_offset, node); + } + + JUMP => { + cfg.graph.add_edge(node, cfg.jump_table, Branch::Dynamic); + + node = cfg.graph.add_node(BasicBlock::linear_at(index + 1)); } JUMPI => { - // Conclude this bb; if we are not already in a bb we must create a new one - let mut node = current_block.take().unwrap_or_else(|| BasicBlock { - opcodes: Range { - start: index, - end: index + 1, - }, - ..Default::default() - }); - node.instructions.extend(instructions); - node.opcodes.end = index + 1; + cfg.graph.add_edge(node, cfg.jump_table, Branch::Dynamic); - let entry = node.entry.clone(); - let node_index = cfg.add_node(node); - - // If the block had an entry, add an edge from the previous block to it - if let Some(Entry::Else(incoming)) | Some(Entry::Jumpdest(incoming)) = entry { - cfg.add_edge(incoming, node_index, Jump::Direct); - } - - // JUMPI implicitly starts a new bb for the else branch - current_block = Some(BasicBlock { - entry: Some(Entry::Else(node_index)), - opcodes: Range { - start: index + 1, - end: index + 1, - }, - ..Default::default() - }); + let previous_node = node; + node = cfg.graph.add_node(BasicBlock::linear_at(index + 1)); + cfg.graph.add_edge(previous_node, node, Branch::Static); } - _ => current_block - .get_or_insert(BasicBlock { - opcodes: Range { - start: index, - end: index + 1, - }, - ..Default::default() - }) - .instructions - .extend(instructions), + STOP | RETURN | REVERT | INVALID | SELFDESTRUCT => { + cfg.graph.add_edge(node, cfg.terminator, Branch::Static); + + node = cfg.graph.add_node(BasicBlock::linear_at(index + 1)); + } + + _ => {} } + + bytecode_offset += opcode.length(); } Self { evm_instructions, cfg, - symbol_table, + symbol_table: Default::default(), + jump_targets, } } + pub fn optimize(&mut self) { + DeadCodeElimination::run(&mut Default::default(), self); + BytecodeLifter::run(&mut Default::default(), self); + DeadCodeElimination::run(&mut Default::default(), self) + } + pub fn dot(&self, format_options: BasicBlockFormatOption) { - let get_node_attrs = move |_, (_, node): (_, &BasicBlock)| { - format!( - "label = \"{}\"", - node.format(&self.evm_instructions, format_options) - ) + let get_node_attrs = move |_, (index, node): (_, &BasicBlock)| { + let (color, shape, label) = if index == self.cfg.terminator { + ("red", "oval", "Terminator".to_string()) + } else if index == self.cfg.start { + ("red", "oval", "Start".to_string()) + } else if index == self.cfg.invalid_jump { + ("blue", "hexagon", "Invalid jump target".to_string()) + } else if index == self.cfg.jump_table { + ("blue", "diamond", "Dynamic jump table".to_string()) + } else { + let instructions = node.format(&self.evm_instructions, format_options); + let start = &self.evm_instructions[node.opcodes.start].bytecode_offset; + let end = &self + .evm_instructions + .get(node.opcodes.end) + .unwrap_or_else(|| &self.evm_instructions[node.opcodes.end - 1]) + .bytecode_offset; + ( + "black", + "rectangle", + format!("Bytecode (0x{start:02x}, 0x{end:02x}]\n---\n{instructions}",), + ) + }; + + format!("color={color} shape={shape} label=\"{label}\"",) + }; + + let get_edge_attrs = |_, edge: petgraph::stable_graph::EdgeReference<'_, Branch>| { + let style = match edge.weight() { + Branch::Static => "solid", + Branch::Dynamic => "dashed", + }; + format!("style={style}") }; let dot = Dot::with_attr_getters( - &self.cfg, + &self.cfg.graph, &[Config::EdgeNoLabel, Config::NodeNoLabel], - &|_, edge| format!("label = \"{:?}\"", edge.weight()), + &get_edge_attrs, &get_node_attrs, ); diff --git a/crates/ir/src/instruction.rs b/crates/ir/src/instruction.rs index 6b3d37a..d6383f0 100644 --- a/crates/ir/src/instruction.rs +++ b/crates/ir/src/instruction.rs @@ -1,67 +1,68 @@ -use evmil::bytecode::Instruction as EvmInstruction; -use primitive_types::U256; +use crate::symbol::{Global, SymbolRef}; use std::fmt::Write; -use crate::{ - symbol::{Global, Symbol, SymbolTable, Type}, - POINTER_SIZE, -}; - #[derive(PartialEq, Debug)] pub enum Instruction { + Nop, + /// `x = y op z` BinaryAssign { - x: Symbol, - y: Symbol, + x: SymbolRef, + y: SymbolRef, operator: Operator, - z: Symbol, + z: SymbolRef, }, /// `x = op y` UnaryAssign { - x: Symbol, + x: SymbolRef, operator: Operator, - y: Symbol, + y: SymbolRef, }, /// `branch target` - UncoditionalBranch { target: Symbol }, + UncoditionalBranch { + target: SymbolRef, + }, /// `branch target if condition` - ConditionalBranch { condition: Symbol, target: Symbol }, + ConditionalBranch { + condition: SymbolRef, + target: SymbolRef, + }, /// `call(label, n)` Procedure { symbol: Global, - parameters: Vec, + parameters: Vec, }, /// `x = call(label, n)` Function { symbol: Global, - x: Symbol, - parameters: Vec, + x: SymbolRef, + parameters: Vec, }, /// `x = y` - Copy { x: Symbol, y: Symbol }, + Copy { + x: SymbolRef, + y: SymbolRef, + }, /// `x[index] = y` - IndexedAssign { x: Symbol, index: Symbol, y: Symbol }, + IndexedAssign { + x: SymbolRef, + index: SymbolRef, + y: SymbolRef, + }, /// `x = y[index]` - IndexedCopy { x: Symbol, y: Symbol, index: Symbol }, -} - -impl Instruction { - fn target_address(&self) -> Symbol { - match self { - Instruction::Copy { x, .. } => *x, - Instruction::IndexedAssign { x, .. } => *x, - Instruction::IndexedCopy { x, .. } => *x, - _ => unreachable!(), - } - } + IndexedCopy { + x: SymbolRef, + y: SymbolRef, + index: SymbolRef, + }, } impl std::fmt::Display for Instruction { @@ -104,6 +105,8 @@ impl std::fmt::Display for Instruction { Self::IndexedAssign { x, index, y } => write!(f, "{x}[{index}] = {y}"), Self::IndexedCopy { x, y, index } => write!(f, "{x} = {y}[{index}]"), + + Self::Nop => write!(f, "no-op"), } } } @@ -122,11 +125,11 @@ pub enum Operator { Exp, SignExtend, - LessThat, + LessThan, GreaterThan, SignedLessThan, SignedGreaterThan, - Eq, + Equal, IsZero, And, @@ -138,273 +141,3 @@ pub enum Operator { ShiftRight, ShiftArithmeticRight, } - -struct StackPop { - decrement: Instruction, - load: Instruction, -} - -/// Pop a value from the stack. -/// -/// Returns 2 `Instruction`: Decrementing the stack pointer and the value copy. -fn stack_pop(symbol_table: &mut SymbolTable) -> StackPop { - let decrement = decrement_stack_height(symbol_table); - - let load = Instruction::IndexedCopy { - x: symbol_table.temporary(None), - y: symbol_table.global(Global::Stack), - index: symbol_table.global(Global::StackHeight), - }; - - StackPop { decrement, load } -} - -/// Decrease the stack height by one. -fn decrement_stack_height(symbol_table: &mut SymbolTable) -> Instruction { - Instruction::BinaryAssign { - x: symbol_table.global(Global::StackHeight), - y: symbol_table.global(Global::StackHeight), - operator: Operator::Sub, - z: symbol_table.constant(U256::one(), Some(Global::StackHeight.typ())), - } -} - -struct StackPush { - assign: Instruction, - increment: Instruction, -} - -/// Push a `value` to the stack. -/// -/// Returns 2 `Instruction`: the value assign and the stack height increase. -fn stack_push(symbol_table: &mut SymbolTable, value: Symbol) -> StackPush { - let assign = Instruction::IndexedAssign { - x: symbol_table.global(Global::Stack), - index: symbol_table.global(Global::StackHeight), - y: value, - }; - let increment = increment_stack_height(symbol_table); - - StackPush { assign, increment } -} - -/// Increment the stack height by one. -fn increment_stack_height(symbol_table: &mut SymbolTable) -> Instruction { - Instruction::BinaryAssign { - x: symbol_table.global(Global::StackHeight), - y: symbol_table.global(Global::StackHeight), - operator: Operator::Add, - z: symbol_table.constant(U256::one(), Some(Global::StackHeight.typ())), - } -} - -/// Lower an EVM instruction into corresponding 3AC instructions. -pub fn translate(opcode: &EvmInstruction, symbol_table: &mut SymbolTable) -> Vec { - use EvmInstruction::*; - match opcode { - JUMPDEST => Vec::new(), - - PUSH(bytes) => { - let type_hint = Some(Type::Bytes(bytes.len())); - let value = symbol_table.constant(U256::from_big_endian(bytes), type_hint); - let push = stack_push(symbol_table, value); - - vec![push.assign, push.increment] - } - - POP => vec![decrement_stack_height(symbol_table)], - - MSTORE => { - let offset = stack_pop(symbol_table); - let value = stack_pop(symbol_table); - - let store = Instruction::IndexedAssign { - x: symbol_table.global(Global::Memory), - index: offset.load.target_address(), - y: value.load.target_address(), - }; - - vec![ - offset.decrement, - offset.load, - value.decrement, - value.load, - store, - ] - } - - JUMP => { - let target = stack_pop(symbol_table); - - let jump = Instruction::UncoditionalBranch { - target: target.load.target_address(), - }; - - vec![target.decrement, target.load, jump] - } - - RETURN => { - let offset = stack_pop(symbol_table); - let size = stack_pop(symbol_table); - - let procedure = Instruction::Procedure { - symbol: Global::Return, - parameters: vec![offset.load.target_address(), size.load.target_address()], - }; - - vec![ - offset.decrement, - offset.load, - size.decrement, - size.load, - procedure, - ] - } - - CALLDATACOPY => { - let destination_offset = stack_pop(symbol_table); - let offset = stack_pop(symbol_table); - let size = stack_pop(symbol_table); - - let parameters = vec![ - destination_offset.load.target_address(), - offset.load.target_address(), - size.load.target_address(), - ]; - - let procedure = Instruction::Procedure { - symbol: Global::MemoryCopy, - parameters, - }; - - vec![ - destination_offset.decrement, - destination_offset.load, - offset.decrement, - offset.load, - size.decrement, - size.load, - procedure, - ] - } - - CALLDATALOAD => { - let index = stack_pop(symbol_table); - - let value = Instruction::IndexedCopy { - x: symbol_table.temporary(None), - y: symbol_table.global(Global::CallData), - index: index.load.target_address(), - }; - - let push = stack_push(symbol_table, value.target_address()); - - vec![ - index.decrement, - index.load, - value, - push.assign, - push.increment, - ] - } - - STOP => { - vec![Instruction::Procedure { - symbol: Global::Stop, - parameters: Default::default(), - }] - } - - INVALID => { - let offset = symbol_table.constant(U256::zero(), Some(Type::Int(POINTER_SIZE))); - let size = symbol_table.constant(U256::zero(), Some(Type::Int(POINTER_SIZE))); - - vec![Instruction::Procedure { - symbol: Global::Revert, - parameters: vec![offset, size], - }] - } - - REVERT => { - let offset = stack_pop(symbol_table); - let size = stack_pop(symbol_table); - - let procedure = Instruction::Procedure { - symbol: Global::Revert, - parameters: vec![offset.load.target_address(), size.load.target_address()], - }; - - vec![ - offset.decrement, - offset.load, - size.decrement, - size.load, - procedure, - ] - } - - //_ => todo!("{opcode}"), - _ => Vec::new(), - } -} - -#[cfg(test)] -mod tests { - use evmil::bytecode; - use primitive_types::U256; - - use crate::{ - instruction::Operator, - symbol::{Address, Global, Kind, Symbol, Type}, - }; - - use super::Instruction; - - #[test] - fn lower_push_works() { - let mut symbol_table = Default::default(); - - let opcode = bytecode::Instruction::PUSH(vec![0x01]); - let result = super::translate(&opcode, &mut symbol_table); - - let expected = vec![ - Instruction::IndexedAssign { - x: Symbol { - address: Address::Label(Global::Stack), - type_hint: Global::Stack.typ(), - kind: Global::Stack.kind(), - }, - index: Symbol { - address: Address::Label(Global::StackHeight), - type_hint: Global::StackHeight.typ(), - kind: Global::StackHeight.kind(), - }, - y: Symbol { - address: Address::Constant(U256::one()), - type_hint: Type::Bytes(1), - kind: Kind::Value, - }, - }, - Instruction::BinaryAssign { - x: Symbol { - address: Address::Label(Global::StackHeight), - type_hint: Global::StackHeight.typ(), - kind: Global::StackHeight.kind(), - }, - y: Symbol { - address: Address::Label(Global::StackHeight), - type_hint: Global::StackHeight.typ(), - kind: Global::StackHeight.kind(), - }, - operator: Operator::Add, - z: Symbol { - address: Address::Constant(U256::one()), - type_hint: Global::StackHeight.typ(), - kind: Kind::Value, - }, - }, - ]; - - assert_eq!(expected, result); - } -} diff --git a/crates/ir/src/lib.rs b/crates/ir/src/lib.rs index cda4348..58c56c2 100644 --- a/crates/ir/src/lib.rs +++ b/crates/ir/src/lib.rs @@ -1,5 +1,7 @@ +pub mod analysis; pub mod cfg; pub mod instruction; +pub mod pass; pub mod symbol; pub static POINTER_SIZE: usize = 32; diff --git a/crates/ir/src/pass/dead_code.rs b/crates/ir/src/pass/dead_code.rs new file mode 100644 index 0000000..7533175 --- /dev/null +++ b/crates/ir/src/pass/dead_code.rs @@ -0,0 +1,15 @@ +use crate::{ + analysis::{analyze, control_flow::ReachableCode}, + cfg::Program, +}; + +use super::Pass; + +#[derive(Default)] +pub struct DeadCodeElimination; + +impl Pass for DeadCodeElimination { + fn run(&mut self, program: &mut Program) { + analyze::(program); + } +} diff --git a/crates/ir/src/pass/lift.rs b/crates/ir/src/pass/lift.rs new file mode 100644 index 0000000..db54899 --- /dev/null +++ b/crates/ir/src/pass/lift.rs @@ -0,0 +1,19 @@ +use crate::{ + analysis::{ + analyze, control_flow::StaticJumps, evm_bytecode::IrBuilder, types::TypePropagation, + }, + cfg::Program, +}; + +use super::Pass; + +#[derive(Default)] +pub struct BytecodeLifter; + +impl Pass for BytecodeLifter { + fn run(&mut self, program: &mut Program) { + analyze::(program); + analyze::(program); + analyze::(program); + } +} diff --git a/crates/ir/src/pass/mod.rs b/crates/ir/src/pass/mod.rs new file mode 100644 index 0000000..3f136d9 --- /dev/null +++ b/crates/ir/src/pass/mod.rs @@ -0,0 +1,8 @@ +use crate::cfg::Program; + +pub mod dead_code; +pub mod lift; + +pub trait Pass: Default { + fn run(&mut self, program: &mut Program); +} diff --git a/crates/ir/src/symbol.rs b/crates/ir/src/symbol.rs index 147fbc4..72d665b 100644 --- a/crates/ir/src/symbol.rs +++ b/crates/ir/src/symbol.rs @@ -1,53 +1,136 @@ -use indexmap::IndexSet; +use indexmap::IndexMap; +use petgraph::prelude::NodeIndex; use primitive_types::U256; +use std::{cell::RefCell, rc::Rc}; use crate::POINTER_SIZE; #[derive(Debug, Default)] pub struct SymbolTable { - symbols: IndexSet, - nonce: usize, + table: IndexMap>>>, + symbols: IndexMap>>, + global_scope: NodeIndex, + id_nonce: usize, } impl SymbolTable { + pub fn merge_scopes(&mut self, node: NodeIndex, target: NodeIndex) { + let sym = self.symbols.remove(&0).unwrap(); + let new = self + .table + .get(&NodeIndex::default()) + .unwrap() + .get(&0) + .unwrap(); + //RefCell::replace(&sym, Rc::clone(new)); + } + + pub fn get_symbol(&self, id: usize) -> SymbolRef { + SymbolRef { + inner: self.symbols.get(&id).unwrap().clone(), + id, + } + } + + pub fn insert(&mut self, scope: NodeIndex, symbol: Symbol) -> SymbolRef { + let id = self.next(); + let inner = Rc::new(RefCell::new(symbol)); + + self.table + .entry(scope) + .or_default() + .insert(id, Rc::clone(&inner)); + self.symbols.insert(id, inner.clone()); + + SymbolRef { inner, id } + } + + pub fn global(&mut self, label: Global) -> SymbolRef { + self.table + .entry(self.global_scope) + .or_default() + .iter() + .find(|(_, symbol)| symbol.borrow().address == Address::Label(label)) + .map(|(id, _)| *id) + .map(|id| self.get_symbol(id)) + .unwrap_or_else(|| self.insert(self.global_scope, Symbol::builder().global(label))) + } + + pub fn temporary(&mut self, node: NodeIndex) -> SymbolRef { + self.insert(node, Symbol::builder().temporary().variable().done()) + } + fn next(&mut self) -> usize { - let current = self.nonce; - self.nonce += 1; + let current = self.id_nonce; + self.id_nonce += 1; current } +} - pub fn temporary(&mut self, type_hint: Option) -> Symbol { - let id = self.next(); - let symbol = Symbol { - address: Address::Temporary(id), - type_hint: type_hint.unwrap_or_default(), - kind: Kind::Value, - }; - assert!(self.symbols.insert(symbol)); +#[derive(Default)] +pub struct SymbolBuilder { + address: A, + type_hint: Type, + kind: K, +} - symbol +impl SymbolBuilder<(), K> { + pub fn temporary(self) -> SymbolBuilder { + SymbolBuilder { + address: Address::Temporary, + type_hint: self.type_hint, + kind: self.kind, + } } - pub fn constant(&mut self, value: U256, type_hint: Option) -> Symbol { - let symbol = Symbol { - address: Address::Constant(value), - type_hint: type_hint.unwrap_or_default(), - kind: Kind::Value, - }; - self.symbols.insert(symbol); - - symbol + pub fn stack(self, slot: i32) -> SymbolBuilder { + SymbolBuilder { + address: Address::Stack(slot), + type_hint: self.type_hint, + kind: self.kind, + } } - pub fn global(&mut self, label: Global) -> Symbol { - let symbol = Symbol { + pub fn global(self, label: Global) -> Symbol { + Symbol { address: Address::Label(label), type_hint: label.typ(), kind: label.kind(), - }; - self.symbols.insert(symbol); + } + } +} - symbol +impl SymbolBuilder { + pub fn constant(self, bytes: &[u8]) -> SymbolBuilder { + SymbolBuilder { + address: self.address, + type_hint: Type::Bytes(bytes.len()), + kind: Kind::Constant(U256::from_big_endian(bytes)), + } + } + + pub fn variable(self) -> SymbolBuilder { + SymbolBuilder { + address: self.address, + type_hint: self.type_hint, + kind: Kind::Variable, + } + } +} + +impl SymbolBuilder { + pub fn of(self, type_hint: Type) -> Self { + Self { type_hint, ..self } + } +} + +impl SymbolBuilder { + pub fn done(self) -> Symbol { + Symbol { + address: self.address, + type_hint: self.type_hint, + kind: self.kind, + } } } @@ -58,40 +141,76 @@ pub struct Symbol { pub kind: Kind, } -impl std::fmt::Display for Symbol { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "({} {})", self.type_hint, self.address)?; +impl Symbol { + pub fn builder() -> SymbolBuilder { + Default::default() + } +} - match self.kind { - Kind::Pointer => write!(f, "*"), - _ => Ok(()), +#[derive(Clone, Debug)] +pub struct SymbolRef { + inner: Rc>, + id: usize, +} + +impl std::fmt::Display for SymbolRef { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let symbol = self.symbol(); + + let address = format!("${}_{}", self.id, symbol.address); + + match symbol.kind { + Kind::Pointer => write!(f, "*{address}"), + Kind::Constant(value) => { + write!(f, "{} {address} := {value}", symbol.type_hint) + } + _ => write!(f, "{} {address} ", symbol.type_hint), } } } -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +impl SymbolRef { + pub fn replace_type(&self, type_hint: Type) { + self.inner.replace_with(|old| Symbol { + address: old.address, + kind: old.kind, + type_hint, + }); + } + + pub fn symbol(&self) -> Symbol { + *self.inner.borrow() + } + + pub fn id(&self) -> usize { + self.id + } +} + +impl PartialEq for SymbolRef { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + +#[derive(Default, Debug, PartialEq, Eq, Hash, Clone, Copy)] pub enum Address { - Constant(U256), - Temporary(usize), + #[default] + Temporary, + Stack(i32), Label(Global), } impl std::fmt::Display for Address { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Constant(value) => write!(f, "0x{value:02x}"), - Self::Temporary(n) => write!(f, "tmp_{n}"), + Self::Stack(slot) => write!(f, "stack[{slot}]"), + Self::Temporary => write!(f, "tmp"), Self::Label(label) => write!(f, "{label:?}"), } } } -impl Address { - pub fn from_be_bytes(bytes: &[u8]) -> Self { - Self::Constant(U256::from_big_endian(bytes)) - } -} - #[derive(Debug, PartialEq, Eq, Hash, Default, Clone, Copy)] pub enum Type { #[default] @@ -120,10 +239,12 @@ impl Type { } } -#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +#[derive(Default, Debug, PartialEq, Eq, Hash, Clone, Copy)] pub enum Kind { Pointer, - Value, + #[default] + Variable, + Constant(U256), Function, } @@ -189,7 +310,7 @@ impl Global { pub fn kind(&self) -> Kind { match self { Self::Stack | Self::CallData | Self::Memory | Self::ReturnData => Kind::Pointer, - Self::StackHeight => Kind::Value, + Self::StackHeight => Kind::Variable, _ => Kind::Function, } } diff --git a/crates/lld-sys/build.rs b/crates/lld-sys/build.rs index ddd234b..69e8753 100644 --- a/crates/lld-sys/build.rs +++ b/crates/lld-sys/build.rs @@ -1,25 +1,27 @@ -// SPDX-License-Identifier: Apache-2.0 +fn llvm_config(arg: &str) -> String { + let output = std::process::Command::new("llvm-config") + .args([arg]) + .output() + .unwrap_or_else(|_| panic!("`llvm-config {arg}` failed")); -use std::{io::Read, process::Command}; + String::from_utf8(output.stdout) + .unwrap_or_else(|_| panic!("output of `llvm-config {arg}` should be utf8")) +} fn main() { - let mut flags = String::new(); - Command::new("llvm-config") - .args(["--cxxflags"]) - .output() - .expect("llvm-config should be able to provide CXX flags") - .stdout - .as_slice() - .read_to_string(&mut flags) - .expect("llvm-config output should be utf8"); - let mut builder = cc::Build::new(); - flags + llvm_config("--cxxflags") .split_whitespace() .fold(&mut builder, |builder, flag| builder.flag(flag)) .cpp(true) .file("src/linker.cpp") .compile("liblinker.a"); + println!("cargo:rustc-link-search=native={}", llvm_config("--libdir")); + + for lib in ["lldELF", "lldCommon", "lldMachO"] { + println!("cargo:rustc-link-lib=static={lib}"); + } + println!("cargo:rerun-if-changed=build.rs"); } diff --git a/crates/lld-sys/src/linker.cpp b/crates/lld-sys/src/linker.cpp index 05a5f5a..11dbd54 100644 --- a/crates/lld-sys/src/linker.cpp +++ b/crates/lld-sys/src/linker.cpp @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: Apache-2.0 - #include "lld/Common/Driver.h" #include "lld/Common/CommonLinkerContext.h" #include "llvm/Support/CrashRecoveryContext.h" @@ -19,4 +17,4 @@ extern "C" bool LLDELFLink(const char *argv[], size_t length) llvm::CrashRecoveryContext crc; return canRunAgain && crc.RunSafely([&]() { lld::CommonLinkerContext::destroy(); }); -} \ No newline at end of file +} diff --git a/crates/polkavm/src/lib.rs b/crates/polkavm/src/lib.rs deleted file mode 100644 index 7d12d9a..0000000 --- a/crates/polkavm/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/crates/target-polkavm/Cargo.toml b/crates/target-polkavm/Cargo.toml new file mode 100644 index 0000000..03021e0 --- /dev/null +++ b/crates/target-polkavm/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "revive-target-polkavm" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +inkwell = { workspace = true } +tempfile = { workspace = true } +polkavm-linker = { workspace = true } +polkavm-common = { workspace = true } +libc = { workspace = true } + +revive-codegen = { path = "../codegen" } +revive-compilation-target = { path = "../compilation-target" } +revive-builtins = { path = "../builtins" } +lld-sys = { path = "../lld-sys" } diff --git a/crates/target-polkavm/polkavm_guest.bc b/crates/target-polkavm/polkavm_guest.bc new file mode 100644 index 0000000000000000000000000000000000000000..fa532df633916d34b72cbeff3e06c7f23c3454f2 GIT binary patch literal 36020 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 Aod5s; literal 0 HcmV?d00001 diff --git a/crates/target-polkavm/src/environment.rs b/crates/target-polkavm/src/environment.rs new file mode 100644 index 0000000..4ab479e --- /dev/null +++ b/crates/target-polkavm/src/environment.rs @@ -0,0 +1,77 @@ +use inkwell::{builder::Builder, context::Context, module::Module, values::FunctionValue}; +use polkavm_common::elf::FnMetadata; + +use revive_compilation_target::environment::Environment; +use revive_compilation_target::target::Target; + +use crate::PolkaVm; + +impl<'ctx> Environment<'ctx> for PolkaVm { + fn call_start(&'ctx self, builder: &Builder<'ctx>, start: FunctionValue<'ctx>) -> Module<'ctx> { + let module = self.context().create_module("entrypoint"); + + let (call, deploy) = pvm_exports(&self.0); + module.link_in_module(call).unwrap(); + module.link_in_module(deploy).unwrap(); + + let function_type = self.context().void_type().fn_type(&[], false); + + let call = module.add_function("call", function_type, None); + call.set_section(Some(".text.polkavm_export")); + builder.position_at_end(self.context().append_basic_block(call, "entry")); + builder.build_call(start, &[], "call_start"); + builder.build_return(None); + + let deploy = module.add_function("deploy", function_type, None); + deploy.set_section(Some(".text.polkavm_export")); + builder.position_at_end(self.context().append_basic_block(deploy, "entry")); + builder.build_unreachable(); + builder.build_return(None); + + module + } +} + +pub(super) fn pvm_exports(context: &Context) -> (Module, Module) { + let call_m = context.create_module("pvm_call"); + let deploy_m = context.create_module("pvm_deploy"); + + call_m.set_inline_assembly(&generate_export_assembly("call")); + deploy_m.set_inline_assembly(&generate_export_assembly("deploy")); + + (call_m, deploy_m) +} + +fn generate_export_assembly(symbol: &str) -> String { + let mut assembly = String::new(); + + assembly.push_str(".pushsection .polkavm_exports,\"\",@progbits\n"); + assembly.push_str(".byte 1\n"); // Version. + assembly.push_str(&format!(".4byte {symbol}\n")); // Address + + // Metadata + let mut metadata = Vec::new(); + FnMetadata { + name: symbol.to_string(), + args: Default::default(), + return_ty: Default::default(), + } + .serialize(|slice| metadata.extend_from_slice(slice)); + + assembly.push_str(&bytes_to_asm(&metadata)); + + assembly.push_str(".popsection\n"); + + assembly +} + +pub fn bytes_to_asm(bytes: &[u8]) -> String { + use std::fmt::Write; + + let mut out = String::with_capacity(bytes.len() * 11); + for &byte in bytes { + writeln!(&mut out, ".byte 0x{:02x}", byte).unwrap(); + } + + out +} diff --git a/crates/target-polkavm/src/lib.rs b/crates/target-polkavm/src/lib.rs new file mode 100644 index 0000000..2765ea8 --- /dev/null +++ b/crates/target-polkavm/src/lib.rs @@ -0,0 +1,13 @@ +use inkwell::context::Context; + +pub mod environment; +pub mod linker; +pub mod target; + +pub struct PolkaVm(Context); + +impl Default for PolkaVm { + fn default() -> Self { + Self(Context::create()) + } +} diff --git a/crates/target-polkavm/src/linker.rs b/crates/target-polkavm/src/linker.rs new file mode 100644 index 0000000..1961595 --- /dev/null +++ b/crates/target-polkavm/src/linker.rs @@ -0,0 +1,86 @@ +use std::{ffi::CString, fs}; + +use lld_sys::LLDELFLink; +use revive_builtins::COMPILER_RT; + +const LINKER_SCRIPT: &str = r#" +SECTIONS { + . = 0x10000; + .rodata : { *(.rodata) *(.rodata.*) } + .data.rel.ro : { *(.data.rel.ro) *(.data.rel.ro.*) } + .got : { *(.got) *(.got.*) } + + . = ALIGN(0x4000); + .data : { *(.sdata) *(.data) } + .bss : { *(.sbss) *(.bss) *(.bss.*) } + + . = 0xf0000000; + + .text : { KEEP(*(.text.polkavm_export)) *(.text .text.*) } + + /DISCARD/ : { *(.eh_frame) } + . = ALIGN(4); +}"#; + +fn invoke_lld(cmd_args: &[&str]) -> bool { + let c_strings = cmd_args + .iter() + .map(|arg| CString::new(*arg).expect("ld.lld args should not contain null bytes")) + .collect::>(); + + let args: Vec<*const libc::c_char> = c_strings.iter().map(|arg| arg.as_ptr()).collect(); + + unsafe { LLDELFLink(args.as_ptr(), args.len()) == 0 } +} + +fn polkavm_linker(code: &[u8]) -> Vec { + let mut config = polkavm_linker::Config::default(); + config.set_strip(true); + + match polkavm_linker::program_from_elf(config, code) { + Ok(blob) => blob.as_bytes().to_vec(), + Err(reason) => panic!("polkavm linker failed: {}", reason), + } +} + +pub(crate) fn link(input: &[u8]) -> Vec { + let dir = tempfile::tempdir().expect("failed to create temp directory for linking"); + let output_path = dir.path().join("out.so"); + let object_path = dir.path().join("out.o"); + let linker_script_path = dir.path().join("linker.ld"); + let compiler_rt_path = dir.path().join("libclang_rt.builtins-riscv32.a"); + + fs::write(&object_path, input).unwrap_or_else(|msg| panic!("{msg} {object_path:?}")); + + fs::write(&linker_script_path, LINKER_SCRIPT) + .unwrap_or_else(|msg| panic!("{msg} {linker_script_path:?}")); + + fs::write(&compiler_rt_path, COMPILER_RT) + .unwrap_or_else(|msg| panic!("{msg} {compiler_rt_path:?}")); + + let ld_args = [ + "ld.lld", + "--error-limit=0", + "--relocatable", + "--emit-relocs", + "--no-relax", + "--gc-sections", + "--library-path", + dir.path().to_str().expect("should be utf8"), + "--library", + "clang_rt.builtins-riscv32", + linker_script_path.to_str().expect("should be utf8"), + object_path.to_str().expect("should be utf8"), + "-o", + output_path.to_str().expect("should be utf8"), + ]; + + assert!(!invoke_lld(&ld_args), "ld.lld failed"); + + fs::copy(&object_path, "/tmp/out.o").unwrap(); + fs::copy(&output_path, "/tmp/out.so").unwrap(); + fs::copy(&linker_script_path, "/tmp/linkder.ld").unwrap(); + + let blob = fs::read(&output_path).expect("ld.lld should produce output"); + polkavm_linker(&blob) +} diff --git a/crates/target-polkavm/src/target.rs b/crates/target-polkavm/src/target.rs new file mode 100644 index 0000000..e070dc3 --- /dev/null +++ b/crates/target-polkavm/src/target.rs @@ -0,0 +1,34 @@ +use inkwell::{ + context::Context, memory_buffer::MemoryBuffer, module::Module, targets::RelocMode, + OptimizationLevel, +}; +use revive_compilation_target::target::Target; + +use crate::PolkaVm; + +impl<'ctx> Target<'ctx> for PolkaVm { + const TARGET_NAME: &'static str = "riscv32"; + const TARGET_TRIPLE: &'static str = "riscv32-unknown-unknown-elf"; + const TARGET_FEATURES: &'static str = "+e,+m"; + const CPU: &'static str = "generic-rv32"; + const RELOC_MODE: RelocMode = RelocMode::PIC; + + fn libraries(&'ctx self) -> Vec> { + let guest_bitcode = include_bytes!("../polkavm_guest.bc"); + let imports = MemoryBuffer::create_from_memory_range(guest_bitcode, "guest_bc"); + + vec![Module::parse_bitcode_from_buffer(&imports, &self.0).unwrap()] + } + + fn context(&self) -> &Context { + &self.0 + } + + fn link(&self, blob: &[u8]) -> Vec { + crate::linker::link(blob) + } + + fn optimization_level(&self) -> OptimizationLevel { + OptimizationLevel::Aggressive + } +} diff --git a/erc20_paris.yul b/erc20_paris.yul new file mode 100644 index 0000000..98afda8 --- /dev/null +++ b/erc20_paris.yul @@ -0,0 +1,2672 @@ +digraph { + 0 [ color=red shape=oval label="Start"] + 1 [ color=blue shape=diamond label="Dynamic jump table"] + 2 [ color=red shape=oval label="Terminator"] + 3 [ color=black shape=rectangle label="Bytecode range: (0x00, 0x08] +--- +PUSH([128]) +PUSH([64]) +MSTORE +CALLVALUE +DUP(1) +ISZERO +PUSH([0, 0, 17]) +JUMPI +"] + 4 [ color=black shape=rectangle label="Bytecode range: (0x08, 0x0b] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 5 [ color=black shape=rectangle label="Bytecode range: (0x0b, 0x20] +--- +JUMPDEST +POP +PUSH([64]) +MLOAD +PUSH([0, 11, 163]) +CODESIZE +SUB +DUP(1) +PUSH([0, 11, 163]) +DUP(4) +CODECOPY +DUP(2) +ADD +PUSH([64]) +DUP(2) +SWAP(1) +MSTORE +PUSH([0, 0, 52]) +SWAP(2) +PUSH([0, 1, 34]) +JUMP +"] + 6 [ color=black shape=rectangle label="Bytecode range: (0x20, 0x27] +--- +JUMPDEST +PUSH([3]) +PUSH([0, 0, 66]) +DUP(4) +DUP(3) +PUSH([0, 2, 29]) +JUMP +"] + 7 [ color=black shape=rectangle label="Bytecode range: (0x27, 0x2f] +--- +JUMPDEST +POP +PUSH([4]) +PUSH([0, 0, 81]) +DUP(3) +DUP(3) +PUSH([0, 2, 29]) +JUMP +"] + 8 [ color=black shape=rectangle label="Bytecode range: (0x2f, 0x35] +--- +JUMPDEST +POP +POP +POP +PUSH([0, 2, 233]) +JUMP +"] + 9 [ color=black shape=rectangle label="Bytecode range: (0x35, 0x41] +--- +JUMPDEST +PUSH([78, 72, 123, 113]) +PUSH([224]) +SHL +PUSH([0]) +MSTORE +PUSH([65]) +PUSH([4]) +MSTORE +PUSH([36]) +PUSH([0]) +REVERT +"] + 10 [ color=black shape=rectangle label="Bytecode range: (0x41, 0x4a] +--- +JUMPDEST +PUSH([0]) +DUP(3) +PUSH([31]) +DUP(4) +ADD +SLT +PUSH([0, 0, 130]) +JUMPI +"] + 11 [ color=black shape=rectangle label="Bytecode range: (0x4a, 0x4d] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 12 [ color=black shape=rectangle label="Bytecode range: (0x4d, 0x5b] +--- +JUMPDEST +DUP(2) +MLOAD +PUSH([1]) +PUSH([1]) +PUSH([64]) +SHL +SUB +DUP(1) +DUP(3) +GT +ISZERO +PUSH([0, 0, 159]) +JUMPI +"] + 13 [ color=black shape=rectangle label="Bytecode range: (0x5b, 0x5e] +--- +PUSH([0, 0, 159]) +PUSH([0, 0, 90]) +JUMP +"] + 14 [ color=black shape=rectangle label="Bytecode range: (0x5e, 0x79] +--- +JUMPDEST +PUSH([64]) +MLOAD +PUSH([31]) +DUP(4) +ADD +PUSH([31]) +NOT +SWAP(1) +DUP(2) +AND +PUSH([63]) +ADD +AND +DUP(2) +ADD +SWAP(1) +DUP(3) +DUP(3) +GT +DUP(2) +DUP(4) +LT +OR +ISZERO +PUSH([0, 0, 202]) +JUMPI +"] + 15 [ color=black shape=rectangle label="Bytecode range: (0x79, 0x7c] +--- +PUSH([0, 0, 202]) +PUSH([0, 0, 90]) +JUMP +"] + 16 [ color=black shape=rectangle label="Bytecode range: (0x7c, 0x90] +--- +JUMPDEST +DUP(2) +PUSH([64]) +MSTORE +DUP(4) +DUP(2) +MSTORE +PUSH([32]) +SWAP(3) +POP +DUP(7) +PUSH([32]) +DUP(6) +DUP(9) +ADD +ADD +GT +ISZERO +PUSH([0, 0, 232]) +JUMPI +"] + 17 [ color=black shape=rectangle label="Bytecode range: (0x90, 0x93] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 18 [ color=black shape=rectangle label="Bytecode range: (0x93, 0x97] +--- +JUMPDEST +PUSH([0]) +SWAP(2) +POP +"] + 19 [ color=black shape=rectangle label="Bytecode range: (0x97, 0x9e] +--- +JUMPDEST +DUP(4) +DUP(3) +LT +ISZERO +PUSH([0, 1, 12]) +JUMPI +"] + 20 [ color=black shape=rectangle label="Bytecode range: (0x9e, 0xb0] +--- +DUP(6) +DUP(3) +ADD +DUP(4) +ADD +MLOAD +DUP(2) +DUP(4) +ADD +DUP(5) +ADD +MSTORE +SWAP(1) +DUP(3) +ADD +SWAP(1) +PUSH([0, 0, 237]) +JUMP +"] + 21 [ color=black shape=rectangle label="Bytecode range: (0xb0, 0xc4] +--- +JUMPDEST +PUSH([0]) +PUSH([32]) +DUP(6) +DUP(4) +ADD +ADD +MSTORE +DUP(1) +SWAP(5) +POP +POP +POP +POP +POP +SWAP(3) +SWAP(2) +POP +POP +JUMP +"] + 22 [ color=black shape=rectangle label="Bytecode range: (0xc4, 0xcf] +--- +JUMPDEST +PUSH([0]) +DUP(1) +PUSH([64]) +DUP(4) +DUP(6) +SUB +SLT +ISZERO +PUSH([0, 1, 54]) +JUMPI +"] + 23 [ color=black shape=rectangle label="Bytecode range: (0xcf, 0xd2] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 24 [ color=black shape=rectangle label="Bytecode range: (0xd2, 0xe0] +--- +JUMPDEST +DUP(3) +MLOAD +PUSH([1]) +PUSH([1]) +PUSH([64]) +SHL +SUB +DUP(1) +DUP(3) +GT +ISZERO +PUSH([0, 1, 78]) +JUMPI +"] + 25 [ color=black shape=rectangle label="Bytecode range: (0xe0, 0xe3] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 26 [ color=black shape=rectangle label="Bytecode range: (0xe3, 0xeb] +--- +JUMPDEST +PUSH([0, 1, 92]) +DUP(7) +DUP(4) +DUP(8) +ADD +PUSH([0, 0, 112]) +JUMP +"] + 27 [ color=black shape=rectangle label="Bytecode range: (0xeb, 0xfa] +--- +JUMPDEST +SWAP(4) +POP +PUSH([32]) +DUP(6) +ADD +MLOAD +SWAP(2) +POP +DUP(1) +DUP(3) +GT +ISZERO +PUSH([0, 1, 115]) +JUMPI +"] + 28 [ color=black shape=rectangle label="Bytecode range: (0xfa, 0xfd] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 29 [ color=black shape=rectangle label="Bytecode range: (0xfd, 0x106] +--- +JUMPDEST +POP +PUSH([0, 1, 130]) +DUP(6) +DUP(3) +DUP(7) +ADD +PUSH([0, 0, 112]) +JUMP +"] + 30 [ color=black shape=rectangle label="Bytecode range: (0x106, 0x110] +--- +JUMPDEST +SWAP(2) +POP +POP +SWAP(3) +POP +SWAP(3) +SWAP(1) +POP +JUMP +"] + 31 [ color=black shape=rectangle label="Bytecode range: (0x110, 0x11b] +--- +JUMPDEST +PUSH([1]) +DUP(2) +DUP(2) +SHR +SWAP(1) +DUP(3) +AND +DUP(1) +PUSH([0, 1, 161]) +JUMPI +"] + 32 [ color=black shape=rectangle label="Bytecode range: (0x11b, 0x120] +--- +PUSH([127]) +DUP(3) +AND +SWAP(2) +POP +"] + 33 [ color=black shape=rectangle label="Bytecode range: (0x120, 0x128] +--- +JUMPDEST +PUSH([32]) +DUP(3) +LT +DUP(2) +SUB +PUSH([0, 1, 194]) +JUMPI +"] + 34 [ color=black shape=rectangle label="Bytecode range: (0x128, 0x133] +--- +PUSH([78, 72, 123, 113]) +PUSH([224]) +SHL +PUSH([0]) +MSTORE +PUSH([34]) +PUSH([4]) +MSTORE +PUSH([36]) +PUSH([0]) +REVERT +"] + 35 [ color=black shape=rectangle label="Bytecode range: (0x133, 0x139] +--- +JUMPDEST +POP +SWAP(2) +SWAP(1) +POP +JUMP +"] + 36 [ color=black shape=rectangle label="Bytecode range: (0x139, 0x140] +--- +JUMPDEST +PUSH([31]) +DUP(3) +GT +ISZERO +PUSH([0, 2, 24]) +JUMPI +"] + 37 [ color=black shape=rectangle label="Bytecode range: (0x140, 0x154] +--- +PUSH([0]) +DUP(2) +PUSH([0]) +MSTORE +PUSH([32]) +PUSH([0]) +KECCAK256 +PUSH([31]) +DUP(6) +ADD +PUSH([5]) +SHR +DUP(2) +ADD +PUSH([32]) +DUP(7) +LT +ISZERO +PUSH([0, 1, 243]) +JUMPI +"] + 38 [ color=black shape=rectangle label="Bytecode range: (0x154, 0x156] +--- +POP +DUP(1) +"] + 39 [ color=black shape=rectangle label="Bytecode range: (0x156, 0x160] +--- +JUMPDEST +PUSH([31]) +DUP(6) +ADD +PUSH([5]) +SHR +DUP(3) +ADD +SWAP(2) +POP +"] + 40 [ color=black shape=rectangle label="Bytecode range: (0x160, 0x167] +--- +JUMPDEST +DUP(2) +DUP(2) +LT +ISZERO +PUSH([0, 2, 20]) +JUMPI +"] + 41 [ color=black shape=rectangle label="Bytecode range: (0x167, 0x16e] +--- +DUP(3) +DUP(2) +SSTORE +PUSH([1]) +ADD +PUSH([0, 1, 255]) +JUMP +"] + 42 [ color=black shape=rectangle label="Bytecode range: (0x16e, 0x172] +--- +JUMPDEST +POP +POP +POP +"] + 43 [ color=black shape=rectangle label="Bytecode range: (0x172, 0x177] +--- +JUMPDEST +POP +POP +POP +JUMP +"] + 44 [ color=black shape=rectangle label="Bytecode range: (0x177, 0x184] +--- +JUMPDEST +DUP(2) +MLOAD +PUSH([1]) +PUSH([1]) +PUSH([64]) +SHL +SUB +DUP(2) +GT +ISZERO +PUSH([0, 2, 57]) +JUMPI +"] + 45 [ color=black shape=rectangle label="Bytecode range: (0x184, 0x187] +--- +PUSH([0, 2, 57]) +PUSH([0, 0, 90]) +JUMP +"] + 46 [ color=black shape=rectangle label="Bytecode range: (0x187, 0x18f] +--- +JUMPDEST +PUSH([0, 2, 81]) +DUP(2) +PUSH([0, 2, 74]) +DUP(5) +SLOAD +PUSH([0, 1, 140]) +JUMP +"] + 47 [ color=black shape=rectangle label="Bytecode range: (0x18f, 0x193] +--- +JUMPDEST +DUP(5) +PUSH([0, 1, 200]) +JUMP +"] + 48 [ color=black shape=rectangle label="Bytecode range: (0x193, 0x19e] +--- +JUMPDEST +PUSH([32]) +DUP(1) +PUSH([31]) +DUP(4) +GT +PUSH([1]) +DUP(2) +EQ +PUSH([0, 2, 137]) +JUMPI +"] + 49 [ color=black shape=rectangle label="Bytecode range: (0x19e, 0x1a3] +--- +PUSH([0]) +DUP(5) +ISZERO +PUSH([0, 2, 112]) +JUMPI +"] + 50 [ color=black shape=rectangle label="Bytecode range: (0x1a3, 0x1a8] +--- +POP +DUP(6) +DUP(4) +ADD +MLOAD +"] + 51 [ color=black shape=rectangle label="Bytecode range: (0x1a8, 0x1bb] +--- +JUMPDEST +PUSH([0]) +NOT +PUSH([3]) +DUP(7) +SWAP(1) +SHL +SHR +NOT +AND +PUSH([1]) +DUP(6) +SWAP(1) +SHL +OR +DUP(6) +SSTORE +PUSH([0, 2, 20]) +JUMP +"] + 52 [ color=black shape=rectangle label="Bytecode range: (0x1bb, 0x1c8] +--- +JUMPDEST +PUSH([0]) +DUP(6) +DUP(2) +MSTORE +PUSH([32]) +DUP(2) +KECCAK256 +PUSH([31]) +NOT +DUP(7) +AND +SWAP(2) +"] + 53 [ color=black shape=rectangle label="Bytecode range: (0x1c8, 0x1cf] +--- +JUMPDEST +DUP(3) +DUP(2) +LT +ISZERO +PUSH([0, 2, 186]) +JUMPI +"] + 54 [ color=black shape=rectangle label="Bytecode range: (0x1cf, 0x1e2] +--- +DUP(9) +DUP(7) +ADD +MLOAD +DUP(3) +SSTORE +SWAP(5) +DUP(5) +ADD +SWAP(5) +PUSH([1]) +SWAP(1) +SWAP(2) +ADD +SWAP(1) +DUP(5) +ADD +PUSH([0, 2, 153]) +JUMP +"] + 55 [ color=black shape=rectangle label="Bytecode range: (0x1e2, 0x1ea] +--- +JUMPDEST +POP +DUP(6) +DUP(3) +LT +ISZERO +PUSH([0, 2, 217]) +JUMPI +"] + 56 [ color=black shape=rectangle label="Bytecode range: (0x1ea, 0x1fb] +--- +DUP(8) +DUP(6) +ADD +MLOAD +PUSH([0]) +NOT +PUSH([3]) +DUP(9) +SWAP(1) +SHL +PUSH([248]) +AND +SHR +NOT +AND +DUP(2) +SSTORE +"] + 57 [ color=black shape=rectangle label="Bytecode range: (0x1fb, 0x20a] +--- +JUMPDEST +POP +POP +POP +POP +POP +PUSH([1]) +SWAP(1) +DUP(2) +SHL +ADD +SWAP(1) +SSTORE +POP +JUMP +"] + 58 [ color=black shape=rectangle label="Bytecode range: (0x20a, 0x212] +--- +JUMPDEST +PUSH([8, 170]) +DUP(1) +PUSH([0, 2, 249]) +PUSH([0]) +CODECOPY +PUSH([0]) +RETURN +"] + 62 [ color=black shape=rectangle label="Bytecode range: (0x21e, 0x225] +--- +JUMPDEST +POP +PUSH([4]) +CALLDATASIZE +LT +PUSH([0, 185]) +JUMPI +"] + 63 [ color=black shape=rectangle label="Bytecode range: (0x225, 0x22e] +--- +PUSH([0]) +CALLDATALOAD +PUSH([224]) +SHR +DUP(1) +PUSH([57, 80, 147, 81]) +GT +PUSH([0, 129]) +JUMPI +"] + 64 [ color=black shape=rectangle label="Bytecode range: (0x22e, 0x233] +--- +DUP(1) +PUSH([164, 87, 194, 215]) +GT +PUSH([0, 91]) +JUMPI +"] + 65 [ color=black shape=rectangle label="Bytecode range: (0x233, 0x238] +--- +DUP(1) +PUSH([164, 87, 194, 215]) +EQ +PUSH([1, 119]) +JUMPI +"] + 66 [ color=black shape=rectangle label="Bytecode range: (0x238, 0x23d] +--- +DUP(1) +PUSH([169, 5, 156, 187]) +EQ +PUSH([1, 138]) +JUMPI +"] + 67 [ color=black shape=rectangle label="Bytecode range: (0x23d, 0x242] +--- +DUP(1) +PUSH([221, 98, 237, 62]) +EQ +PUSH([1, 157]) +JUMPI +"] + 68 [ color=black shape=rectangle label="Bytecode range: (0x242, 0x245] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 69 [ color=black shape=rectangle label="Bytecode range: (0x245, 0x24b] +--- +JUMPDEST +DUP(1) +PUSH([57, 80, 147, 81]) +EQ +PUSH([1, 51]) +JUMPI +"] + 70 [ color=black shape=rectangle label="Bytecode range: (0x24b, 0x250] +--- +DUP(1) +PUSH([112, 160, 130, 49]) +EQ +PUSH([1, 70]) +JUMPI +"] + 71 [ color=black shape=rectangle label="Bytecode range: (0x250, 0x255] +--- +DUP(1) +PUSH([149, 216, 155, 65]) +EQ +PUSH([1, 111]) +JUMPI +"] + 72 [ color=black shape=rectangle label="Bytecode range: (0x255, 0x258] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 73 [ color=black shape=rectangle label="Bytecode range: (0x258, 0x25e] +--- +JUMPDEST +DUP(1) +PUSH([6, 253, 222, 3]) +EQ +PUSH([0, 190]) +JUMPI +"] + 74 [ color=black shape=rectangle label="Bytecode range: (0x25e, 0x263] +--- +DUP(1) +PUSH([9, 94, 167, 179]) +EQ +PUSH([0, 220]) +JUMPI +"] + 75 [ color=black shape=rectangle label="Bytecode range: (0x263, 0x268] +--- +DUP(1) +PUSH([24, 22, 13, 221]) +EQ +PUSH([0, 255]) +JUMPI +"] + 76 [ color=black shape=rectangle label="Bytecode range: (0x268, 0x26d] +--- +DUP(1) +PUSH([35, 184, 114, 221]) +EQ +PUSH([1, 17]) +JUMPI +"] + 77 [ color=black shape=rectangle label="Bytecode range: (0x26d, 0x272] +--- +DUP(1) +PUSH([49, 60, 229, 103]) +EQ +PUSH([1, 36]) +JUMPI +"] + 78 [ color=black shape=rectangle label="Bytecode range: (0x272, 0x276] +--- +JUMPDEST +PUSH([0]) +DUP(1) +REVERT +"] + 79 [ color=black shape=rectangle label="Bytecode range: (0x276, 0x27a] +--- +JUMPDEST +PUSH([0, 198]) +PUSH([1, 214]) +JUMP +"] + 80 [ color=black shape=rectangle label="Bytecode range: (0x27a, 0x282] +--- +JUMPDEST +PUSH([64]) +MLOAD +PUSH([0, 211]) +SWAP(2) +SWAP(1) +PUSH([6, 243]) +JUMP +"] + 81 [ color=black shape=rectangle label="Bytecode range: (0x282, 0x28a] +--- +JUMPDEST +PUSH([64]) +MLOAD +DUP(1) +SWAP(2) +SUB +SWAP(1) +RETURN +"] + 82 [ color=black shape=rectangle label="Bytecode range: (0x28a, 0x291] +--- +JUMPDEST +PUSH([0, 239]) +PUSH([0, 234]) +CALLDATASIZE +PUSH([4]) +PUSH([7, 94]) +JUMP +"] + 83 [ color=black shape=rectangle label="Bytecode range: (0x291, 0x294] +--- +JUMPDEST +PUSH([2, 104]) +JUMP +"] + 84 [ color=black shape=rectangle label="Bytecode range: (0x294, 0x2a0] +--- +JUMPDEST +PUSH([64]) +MLOAD +SWAP(1) +ISZERO +ISZERO +DUP(2) +MSTORE +PUSH([32]) +ADD +PUSH([0, 211]) +JUMP +"] + 85 [ color=black shape=rectangle label="Bytecode range: (0x2a0, 0x2a3] +--- +JUMPDEST +PUSH([2]) +SLOAD +"] + 86 [ color=black shape=rectangle label="Bytecode range: (0x2a3, 0x2ad] +--- +JUMPDEST +PUSH([64]) +MLOAD +SWAP(1) +DUP(2) +MSTORE +PUSH([32]) +ADD +PUSH([0, 211]) +JUMP +"] + 87 [ color=black shape=rectangle label="Bytecode range: (0x2ad, 0x2b4] +--- +JUMPDEST +PUSH([0, 239]) +PUSH([1, 31]) +CALLDATASIZE +PUSH([4]) +PUSH([7, 136]) +JUMP +"] + 88 [ color=black shape=rectangle label="Bytecode range: (0x2b4, 0x2b7] +--- +JUMPDEST +PUSH([2, 130]) +JUMP +"] + 89 [ color=black shape=rectangle label="Bytecode range: (0x2b7, 0x2c1] +--- +JUMPDEST +PUSH([64]) +MLOAD +PUSH([18]) +DUP(2) +MSTORE +PUSH([32]) +ADD +PUSH([0, 211]) +JUMP +"] + 90 [ color=black shape=rectangle label="Bytecode range: (0x2c1, 0x2c8] +--- +JUMPDEST +PUSH([0, 239]) +PUSH([1, 65]) +CALLDATASIZE +PUSH([4]) +PUSH([7, 94]) +JUMP +"] + 91 [ color=black shape=rectangle label="Bytecode range: (0x2c8, 0x2cb] +--- +JUMPDEST +PUSH([2, 166]) +JUMP +"] + 92 [ color=black shape=rectangle label="Bytecode range: (0x2cb, 0x2d2] +--- +JUMPDEST +PUSH([1, 3]) +PUSH([1, 84]) +CALLDATASIZE +PUSH([4]) +PUSH([7, 196]) +JUMP +"] + 93 [ color=black shape=rectangle label="Bytecode range: (0x2d2, 0x2e7] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +AND +PUSH([0]) +SWAP(1) +DUP(2) +MSTORE +PUSH([32]) +DUP(2) +SWAP(1) +MSTORE +PUSH([64]) +SWAP(1) +KECCAK256 +SLOAD +SWAP(1) +JUMP +"] + 94 [ color=black shape=rectangle label="Bytecode range: (0x2e7, 0x2eb] +--- +JUMPDEST +PUSH([0, 198]) +PUSH([2, 229]) +JUMP +"] + 95 [ color=black shape=rectangle label="Bytecode range: (0x2eb, 0x2f2] +--- +JUMPDEST +PUSH([0, 239]) +PUSH([1, 133]) +CALLDATASIZE +PUSH([4]) +PUSH([7, 94]) +JUMP +"] + 96 [ color=black shape=rectangle label="Bytecode range: (0x2f2, 0x2f5] +--- +JUMPDEST +PUSH([2, 244]) +JUMP +"] + 97 [ color=black shape=rectangle label="Bytecode range: (0x2f5, 0x2fc] +--- +JUMPDEST +PUSH([0, 239]) +PUSH([1, 152]) +CALLDATASIZE +PUSH([4]) +PUSH([7, 94]) +JUMP +"] + 98 [ color=black shape=rectangle label="Bytecode range: (0x2fc, 0x2ff] +--- +JUMPDEST +PUSH([3, 139]) +JUMP +"] + 99 [ color=black shape=rectangle label="Bytecode range: (0x2ff, 0x306] +--- +JUMPDEST +PUSH([1, 3]) +PUSH([1, 171]) +CALLDATASIZE +PUSH([4]) +PUSH([7, 230]) +JUMP +"] + 100 [ color=black shape=rectangle label="Bytecode range: (0x306, 0x32a] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +SWAP(2) +DUP(3) +AND +PUSH([0]) +SWAP(1) +DUP(2) +MSTORE +PUSH([1]) +PUSH([32]) +SWAP(1) +DUP(2) +MSTORE +PUSH([64]) +DUP(1) +DUP(4) +KECCAK256 +SWAP(4) +SWAP(1) +SWAP(5) +AND +DUP(3) +MSTORE +SWAP(2) +SWAP(1) +SWAP(2) +MSTORE +KECCAK256 +SLOAD +SWAP(1) +JUMP +"] + 101 [ color=black shape=rectangle label="Bytecode range: (0x32a, 0x333] +--- +JUMPDEST +PUSH([96]) +PUSH([3]) +DUP(1) +SLOAD +PUSH([1, 229]) +SWAP(1) +PUSH([8, 25]) +JUMP +"] + 102 [ color=black shape=rectangle label="Bytecode range: (0x333, 0x355] +--- +JUMPDEST +DUP(1) +PUSH([31]) +ADD +PUSH([32]) +DUP(1) +SWAP(2) +DIV +MUL +PUSH([32]) +ADD +PUSH([64]) +MLOAD +SWAP(1) +DUP(2) +ADD +PUSH([64]) +MSTORE +DUP(1) +SWAP(3) +SWAP(2) +SWAP(1) +DUP(2) +DUP(2) +MSTORE +PUSH([32]) +ADD +DUP(3) +DUP(1) +SLOAD +PUSH([2, 17]) +SWAP(1) +PUSH([8, 25]) +JUMP +"] + 103 [ color=black shape=rectangle label="Bytecode range: (0x355, 0x35a] +--- +JUMPDEST +DUP(1) +ISZERO +PUSH([2, 94]) +JUMPI +"] + 104 [ color=black shape=rectangle label="Bytecode range: (0x35a, 0x35f] +--- +DUP(1) +PUSH([31]) +LT +PUSH([2, 51]) +JUMPI +"] + 105 [ color=black shape=rectangle label="Bytecode range: (0x35f, 0x36d] +--- +PUSH([1, 0]) +DUP(1) +DUP(4) +SLOAD +DIV +MUL +DUP(4) +MSTORE +SWAP(2) +PUSH([32]) +ADD +SWAP(2) +PUSH([2, 94]) +JUMP +"] + 106 [ color=black shape=rectangle label="Bytecode range: (0x36d, 0x378] +--- +JUMPDEST +DUP(3) +ADD +SWAP(2) +SWAP(1) +PUSH([0]) +MSTORE +PUSH([32]) +PUSH([0]) +KECCAK256 +SWAP(1) +"] + 107 [ color=black shape=rectangle label="Bytecode range: (0x378, 0x388] +--- +JUMPDEST +DUP(2) +SLOAD +DUP(2) +MSTORE +SWAP(1) +PUSH([1]) +ADD +SWAP(1) +PUSH([32]) +ADD +DUP(1) +DUP(4) +GT +PUSH([2, 65]) +JUMPI +"] + 108 [ color=black shape=rectangle label="Bytecode range: (0x388, 0x390] +--- +DUP(3) +SWAP(1) +SUB +PUSH([31]) +AND +DUP(3) +ADD +SWAP(2) +"] + 109 [ color=black shape=rectangle label="Bytecode range: (0x390, 0x39a] +--- +JUMPDEST +POP +POP +POP +POP +POP +SWAP(1) +POP +SWAP(1) +JUMP +"] + 110 [ color=black shape=rectangle label="Bytecode range: (0x39a, 0x3a3] +--- +JUMPDEST +PUSH([0]) +CALLER +PUSH([2, 118]) +DUP(2) +DUP(6) +DUP(6) +PUSH([3, 153]) +JUMP +"] + 111 [ color=black shape=rectangle label="Bytecode range: (0x3a3, 0x3a8] +--- +JUMPDEST +PUSH([1]) +SWAP(2) +POP +POP +"] + 112 [ color=black shape=rectangle label="Bytecode range: (0x3a8, 0x3ae] +--- +JUMPDEST +SWAP(3) +SWAP(2) +POP +POP +JUMP +"] + 113 [ color=black shape=rectangle label="Bytecode range: (0x3ae, 0x3b7] +--- +JUMPDEST +PUSH([0]) +CALLER +PUSH([2, 144]) +DUP(6) +DUP(3) +DUP(6) +PUSH([4, 189]) +JUMP +"] + 114 [ color=black shape=rectangle label="Bytecode range: (0x3b7, 0x3be] +--- +JUMPDEST +PUSH([2, 155]) +DUP(6) +DUP(6) +DUP(6) +PUSH([5, 79]) +JUMP +"] + 115 [ color=black shape=rectangle label="Bytecode range: (0x3be, 0x3c8] +--- +JUMPDEST +POP +PUSH([1]) +SWAP(5) +SWAP(4) +POP +POP +POP +POP +JUMP +"] + 116 [ color=black shape=rectangle label="Bytecode range: (0x3c8, 0x3f5] +--- +JUMPDEST +CALLER +PUSH([0]) +DUP(2) +DUP(2) +MSTORE +PUSH([1]) +PUSH([32]) +SWAP(1) +DUP(2) +MSTORE +PUSH([64]) +DUP(1) +DUP(4) +KECCAK256 +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(8) +AND +DUP(5) +MSTORE +SWAP(1) +SWAP(2) +MSTORE +DUP(2) +KECCAK256 +SLOAD +SWAP(1) +SWAP(2) +SWAP(1) +PUSH([2, 118]) +SWAP(1) +DUP(3) +SWAP(1) +DUP(7) +SWAP(1) +PUSH([2, 224]) +SWAP(1) +DUP(8) +SWAP(1) +PUSH([8, 83]) +JUMP +"] + 117 [ color=black shape=rectangle label="Bytecode range: (0x3f5, 0x3f8] +--- +JUMPDEST +PUSH([3, 153]) +JUMP +"] + 118 [ color=black shape=rectangle label="Bytecode range: (0x3f8, 0x401] +--- +JUMPDEST +PUSH([96]) +PUSH([4]) +DUP(1) +SLOAD +PUSH([1, 229]) +SWAP(1) +PUSH([8, 25]) +JUMP +"] + 119 [ color=black shape=rectangle label="Bytecode range: (0x401, 0x428] +--- +JUMPDEST +CALLER +PUSH([0]) +DUP(2) +DUP(2) +MSTORE +PUSH([1]) +PUSH([32]) +SWAP(1) +DUP(2) +MSTORE +PUSH([64]) +DUP(1) +DUP(4) +KECCAK256 +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(8) +AND +DUP(5) +MSTORE +SWAP(1) +SWAP(2) +MSTORE +DUP(2) +KECCAK256 +SLOAD +SWAP(1) +SWAP(2) +SWAP(1) +DUP(4) +DUP(2) +LT +ISZERO +PUSH([3, 126]) +JUMPI +"] + 120 [ color=black shape=rectangle label="Bytecode range: (0x428, 0x447] +--- +PUSH([64]) +MLOAD +PUSH([70, 27, 205]) +PUSH([229]) +SHL +DUP(2) +MSTORE +PUSH([32]) +PUSH([4]) +DUP(3) +ADD +MSTORE +PUSH([37]) +PUSH([36]) +DUP(3) +ADD +MSTORE +PUSH([69, 82, 67, 50, 48, 58, 32, 100, 101, 99, 114, 101, 97, 115, 101, 100, 32, 97, 108, 108, 111, 119, 97, 110, 99, 101, 32, 98, 101, 108, 111, 119]) +PUSH([68]) +DUP(3) +ADD +MSTORE +PUSH([32, 122, 101, 114, 111]) +PUSH([216]) +SHL +PUSH([100]) +DUP(3) +ADD +MSTORE +PUSH([132]) +ADD +"] + 121 [ color=black shape=rectangle label="Bytecode range: (0x447, 0x44f] +--- +JUMPDEST +PUSH([64]) +MLOAD +DUP(1) +SWAP(2) +SUB +SWAP(1) +REVERT +"] + 122 [ color=black shape=rectangle label="Bytecode range: (0x44f, 0x458] +--- +JUMPDEST +PUSH([2, 155]) +DUP(3) +DUP(7) +DUP(7) +DUP(5) +SUB +PUSH([3, 153]) +JUMP +"] + 123 [ color=black shape=rectangle label="Bytecode range: (0x458, 0x461] +--- +JUMPDEST +PUSH([0]) +CALLER +PUSH([2, 118]) +DUP(2) +DUP(6) +DUP(6) +PUSH([5, 79]) +JUMP +"] + 124 [ color=black shape=rectangle label="Bytecode range: (0x461, 0x46b] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(4) +AND +PUSH([3, 251]) +JUMPI +"] + 125 [ color=black shape=rectangle label="Bytecode range: (0x46b, 0x48c] +--- +PUSH([64]) +MLOAD +PUSH([70, 27, 205]) +PUSH([229]) +SHL +DUP(2) +MSTORE +PUSH([32]) +PUSH([4]) +DUP(3) +ADD +MSTORE +PUSH([36]) +DUP(1) +DUP(3) +ADD +MSTORE +PUSH([69, 82, 67, 50, 48, 58, 32, 97, 112, 112, 114, 111, 118, 101, 32, 102, 114, 111, 109, 32, 116, 104, 101, 32, 122, 101, 114, 111, 32, 97, 100, 100]) +PUSH([68]) +DUP(3) +ADD +MSTORE +PUSH([114, 101, 115, 115]) +PUSH([224]) +SHL +PUSH([100]) +DUP(3) +ADD +MSTORE +PUSH([132]) +ADD +PUSH([3, 117]) +JUMP +"] + 126 [ color=black shape=rectangle label="Bytecode range: (0x48c, 0x496] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(3) +AND +PUSH([4, 92]) +JUMPI +"] + 127 [ color=black shape=rectangle label="Bytecode range: (0x496, 0x4b7] +--- +PUSH([64]) +MLOAD +PUSH([70, 27, 205]) +PUSH([229]) +SHL +DUP(2) +MSTORE +PUSH([32]) +PUSH([4]) +DUP(3) +ADD +MSTORE +PUSH([34]) +PUSH([36]) +DUP(3) +ADD +MSTORE +PUSH([69, 82, 67, 50, 48, 58, 32, 97, 112, 112, 114, 111, 118, 101, 32, 116, 111, 32, 116, 104, 101, 32, 122, 101, 114, 111, 32, 97, 100, 100, 114, 101]) +PUSH([68]) +DUP(3) +ADD +MSTORE +PUSH([115, 115]) +PUSH([240]) +SHL +PUSH([100]) +DUP(3) +ADD +MSTORE +PUSH([132]) +ADD +PUSH([3, 117]) +JUMP +"] + 128 [ color=black shape=rectangle label="Bytecode range: (0x4b7, 0x4f0] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(4) +DUP(2) +AND +PUSH([0]) +DUP(2) +DUP(2) +MSTORE +PUSH([1]) +PUSH([32]) +SWAP(1) +DUP(2) +MSTORE +PUSH([64]) +DUP(1) +DUP(4) +KECCAK256 +SWAP(5) +DUP(8) +AND +DUP(1) +DUP(5) +MSTORE +SWAP(5) +DUP(3) +MSTORE +SWAP(2) +DUP(3) +SWAP(1) +KECCAK256 +DUP(6) +SWAP(1) +SSTORE +SWAP(1) +MLOAD +DUP(5) +DUP(2) +MSTORE +PUSH([140, 91, 225, 229, 235, 236, 125, 91, 209, 79, 113, 66, 125, 30, 132, 243, 221, 3, 20, 192, 247, 178, 41, 30, 91, 32, 10, 200, 199, 195, 185, 37]) +SWAP(2) +ADD +PUSH([64]) +MLOAD +DUP(1) +SWAP(2) +SUB +SWAP(1) +LOG(3) +POP +POP +POP +JUMP +"] + 129 [ color=black shape=rectangle label="Bytecode range: (0x4f0, 0x516] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(4) +DUP(2) +AND +PUSH([0]) +SWAP(1) +DUP(2) +MSTORE +PUSH([1]) +PUSH([32]) +SWAP(1) +DUP(2) +MSTORE +PUSH([64]) +DUP(1) +DUP(4) +KECCAK256 +SWAP(4) +DUP(7) +AND +DUP(4) +MSTORE +SWAP(3) +SWAP(1) +MSTORE +KECCAK256 +SLOAD +PUSH([0]) +NOT +DUP(2) +EQ +PUSH([5, 73]) +JUMPI +"] + 130 [ color=black shape=rectangle label="Bytecode range: (0x516, 0x51c] +--- +DUP(2) +DUP(2) +LT +ISZERO +PUSH([5, 60]) +JUMPI +"] + 131 [ color=black shape=rectangle label="Bytecode range: (0x51c, 0x536] +--- +PUSH([64]) +MLOAD +PUSH([70, 27, 205]) +PUSH([229]) +SHL +DUP(2) +MSTORE +PUSH([32]) +PUSH([4]) +DUP(3) +ADD +MSTORE +PUSH([29]) +PUSH([36]) +DUP(3) +ADD +MSTORE +PUSH([69, 82, 67, 50, 48, 58, 32, 105, 110, 115, 117, 102, 102, 105, 99, 105, 101, 110, 116, 32, 97, 108, 108, 111, 119, 97, 110, 99, 101, 0, 0, 0]) +PUSH([68]) +DUP(3) +ADD +MSTORE +PUSH([100]) +ADD +PUSH([3, 117]) +JUMP +"] + 132 [ color=black shape=rectangle label="Bytecode range: (0x536, 0x53f] +--- +JUMPDEST +PUSH([5, 73]) +DUP(5) +DUP(5) +DUP(5) +DUP(5) +SUB +PUSH([3, 153]) +JUMP +"] + 133 [ color=black shape=rectangle label="Bytecode range: (0x53f, 0x545] +--- +JUMPDEST +POP +POP +POP +POP +JUMP +"] + 134 [ color=black shape=rectangle label="Bytecode range: (0x545, 0x54f] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(4) +AND +PUSH([5, 179]) +JUMPI +"] + 135 [ color=black shape=rectangle label="Bytecode range: (0x54f, 0x570] +--- +PUSH([64]) +MLOAD +PUSH([70, 27, 205]) +PUSH([229]) +SHL +DUP(2) +MSTORE +PUSH([32]) +PUSH([4]) +DUP(3) +ADD +MSTORE +PUSH([37]) +PUSH([36]) +DUP(3) +ADD +MSTORE +PUSH([69, 82, 67, 50, 48, 58, 32, 116, 114, 97, 110, 115, 102, 101, 114, 32, 102, 114, 111, 109, 32, 116, 104, 101, 32, 122, 101, 114, 111, 32, 97, 100]) +PUSH([68]) +DUP(3) +ADD +MSTORE +PUSH([100, 114, 101, 115, 115]) +PUSH([216]) +SHL +PUSH([100]) +DUP(3) +ADD +MSTORE +PUSH([132]) +ADD +PUSH([3, 117]) +JUMP +"] + 136 [ color=black shape=rectangle label="Bytecode range: (0x570, 0x57a] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(3) +AND +PUSH([6, 21]) +JUMPI +"] + 137 [ color=black shape=rectangle label="Bytecode range: (0x57a, 0x59b] +--- +PUSH([64]) +MLOAD +PUSH([70, 27, 205]) +PUSH([229]) +SHL +DUP(2) +MSTORE +PUSH([32]) +PUSH([4]) +DUP(3) +ADD +MSTORE +PUSH([35]) +PUSH([36]) +DUP(3) +ADD +MSTORE +PUSH([69, 82, 67, 50, 48, 58, 32, 116, 114, 97, 110, 115, 102, 101, 114, 32, 116, 111, 32, 116, 104, 101, 32, 122, 101, 114, 111, 32, 97, 100, 100, 114]) +PUSH([68]) +DUP(3) +ADD +MSTORE +PUSH([101, 115, 115]) +PUSH([232]) +SHL +PUSH([100]) +DUP(3) +ADD +MSTORE +PUSH([132]) +ADD +PUSH([3, 117]) +JUMP +"] + 138 [ color=black shape=rectangle label="Bytecode range: (0x59b, 0x5b5] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(4) +AND +PUSH([0]) +SWAP(1) +DUP(2) +MSTORE +PUSH([32]) +DUP(2) +SWAP(1) +MSTORE +PUSH([64]) +SWAP(1) +KECCAK256 +SLOAD +DUP(2) +DUP(2) +LT +ISZERO +PUSH([6, 141]) +JUMPI +"] + 139 [ color=black shape=rectangle label="Bytecode range: (0x5b5, 0x5d6] +--- +PUSH([64]) +MLOAD +PUSH([70, 27, 205]) +PUSH([229]) +SHL +DUP(2) +MSTORE +PUSH([32]) +PUSH([4]) +DUP(3) +ADD +MSTORE +PUSH([38]) +PUSH([36]) +DUP(3) +ADD +MSTORE +PUSH([69, 82, 67, 50, 48, 58, 32, 116, 114, 97, 110, 115, 102, 101, 114, 32, 97, 109, 111, 117, 110, 116, 32, 101, 120, 99, 101, 101, 100, 115, 32, 98]) +PUSH([68]) +DUP(3) +ADD +MSTORE +PUSH([97, 108, 97, 110, 99, 101]) +PUSH([208]) +SHL +PUSH([100]) +DUP(3) +ADD +MSTORE +PUSH([132]) +ADD +PUSH([3, 117]) +JUMP +"] + 140 [ color=black shape=rectangle label="Bytecode range: (0x5d6, 0x613] +--- +JUMPDEST +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(5) +DUP(2) +AND +PUSH([0]) +DUP(2) +DUP(2) +MSTORE +PUSH([32]) +DUP(2) +DUP(2) +MSTORE +PUSH([64]) +DUP(1) +DUP(4) +KECCAK256 +DUP(8) +DUP(8) +SUB +SWAP(1) +SSTORE +SWAP(4) +DUP(8) +AND +DUP(1) +DUP(4) +MSTORE +SWAP(2) +DUP(5) +SWAP(1) +KECCAK256 +DUP(1) +SLOAD +DUP(8) +ADD +SWAP(1) +SSTORE +SWAP(3) +MLOAD +DUP(6) +DUP(2) +MSTORE +SWAP(1) +SWAP(3) +PUSH([221, 242, 82, 173, 27, 226, 200, 155, 105, 194, 176, 104, 252, 55, 141, 170, 149, 43, 167, 241, 99, 196, 161, 22, 40, 245, 90, 77, 245, 35, 179, 239]) +SWAP(2) +ADD +PUSH([64]) +MLOAD +DUP(1) +SWAP(2) +SUB +SWAP(1) +LOG(3) +PUSH([5, 73]) +JUMP +"] + 141 [ color=black shape=rectangle label="Bytecode range: (0x613, 0x621] +--- +JUMPDEST +PUSH([0]) +PUSH([32]) +DUP(1) +DUP(4) +MSTORE +DUP(4) +MLOAD +DUP(1) +PUSH([32]) +DUP(6) +ADD +MSTORE +PUSH([0]) +"] + 142 [ color=black shape=rectangle label="Bytecode range: (0x621, 0x628] +--- +JUMPDEST +DUP(2) +DUP(2) +LT +ISZERO +PUSH([7, 33]) +JUMPI +"] + 143 [ color=black shape=rectangle label="Bytecode range: (0x628, 0x638] +--- +DUP(6) +DUP(2) +ADD +DUP(4) +ADD +MLOAD +DUP(6) +DUP(3) +ADD +PUSH([64]) +ADD +MSTORE +DUP(3) +ADD +PUSH([7, 5]) +JUMP +"] + 144 [ color=black shape=rectangle label="Bytecode range: (0x638, 0x654] +--- +JUMPDEST +POP +PUSH([0]) +PUSH([64]) +DUP(3) +DUP(7) +ADD +ADD +MSTORE +PUSH([64]) +PUSH([31]) +NOT +PUSH([31]) +DUP(4) +ADD +AND +DUP(6) +ADD +ADD +SWAP(3) +POP +POP +POP +SWAP(3) +SWAP(2) +POP +POP +JUMP +"] + 145 [ color=black shape=rectangle label="Bytecode range: (0x654, 0x662] +--- +JUMPDEST +DUP(1) +CALLDATALOAD +PUSH([1]) +PUSH([1]) +PUSH([160]) +SHL +SUB +DUP(2) +AND +DUP(2) +EQ +PUSH([7, 89]) +JUMPI +"] + 146 [ color=black shape=rectangle label="Bytecode range: (0x662, 0x665] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 147 [ color=black shape=rectangle label="Bytecode range: (0x665, 0x66a] +--- +JUMPDEST +SWAP(2) +SWAP(1) +POP +JUMP +"] + 148 [ color=black shape=rectangle label="Bytecode range: (0x66a, 0x675] +--- +JUMPDEST +PUSH([0]) +DUP(1) +PUSH([64]) +DUP(4) +DUP(6) +SUB +SLT +ISZERO +PUSH([7, 113]) +JUMPI +"] + 149 [ color=black shape=rectangle label="Bytecode range: (0x675, 0x678] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 150 [ color=black shape=rectangle label="Bytecode range: (0x678, 0x67d] +--- +JUMPDEST +PUSH([7, 122]) +DUP(4) +PUSH([7, 66]) +JUMP +"] + 151 [ color=black shape=rectangle label="Bytecode range: (0x67d, 0x68a] +--- +JUMPDEST +SWAP(5) +PUSH([32]) +SWAP(4) +SWAP(1) +SWAP(4) +ADD +CALLDATALOAD +SWAP(4) +POP +POP +POP +JUMP +"] + 152 [ color=black shape=rectangle label="Bytecode range: (0x68a, 0x696] +--- +JUMPDEST +PUSH([0]) +DUP(1) +PUSH([0]) +PUSH([96]) +DUP(5) +DUP(7) +SUB +SLT +ISZERO +PUSH([7, 157]) +JUMPI +"] + 153 [ color=black shape=rectangle label="Bytecode range: (0x696, 0x699] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 154 [ color=black shape=rectangle label="Bytecode range: (0x699, 0x69e] +--- +JUMPDEST +PUSH([7, 166]) +DUP(5) +PUSH([7, 66]) +JUMP +"] + 155 [ color=black shape=rectangle label="Bytecode range: (0x69e, 0x6a7] +--- +JUMPDEST +SWAP(3) +POP +PUSH([7, 180]) +PUSH([32]) +DUP(6) +ADD +PUSH([7, 66]) +JUMP +"] + 156 [ color=black shape=rectangle label="Bytecode range: (0x6a7, 0x6b6] +--- +JUMPDEST +SWAP(2) +POP +PUSH([64]) +DUP(5) +ADD +CALLDATALOAD +SWAP(1) +POP +SWAP(3) +POP +SWAP(3) +POP +SWAP(3) +JUMP +"] + 157 [ color=black shape=rectangle label="Bytecode range: (0x6b6, 0x6c0] +--- +JUMPDEST +PUSH([0]) +PUSH([32]) +DUP(3) +DUP(5) +SUB +SLT +ISZERO +PUSH([7, 214]) +JUMPI +"] + 158 [ color=black shape=rectangle label="Bytecode range: (0x6c0, 0x6c3] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 159 [ color=black shape=rectangle label="Bytecode range: (0x6c3, 0x6c8] +--- +JUMPDEST +PUSH([7, 223]) +DUP(3) +PUSH([7, 66]) +JUMP +"] + 160 [ color=black shape=rectangle label="Bytecode range: (0x6c8, 0x6cf] +--- +JUMPDEST +SWAP(4) +SWAP(3) +POP +POP +POP +JUMP +"] + 161 [ color=black shape=rectangle label="Bytecode range: (0x6cf, 0x6da] +--- +JUMPDEST +PUSH([0]) +DUP(1) +PUSH([64]) +DUP(4) +DUP(6) +SUB +SLT +ISZERO +PUSH([7, 249]) +JUMPI +"] + 162 [ color=black shape=rectangle label="Bytecode range: (0x6da, 0x6dd] +--- +PUSH([0]) +DUP(1) +REVERT +"] + 163 [ color=black shape=rectangle label="Bytecode range: (0x6dd, 0x6e2] +--- +JUMPDEST +PUSH([8, 2]) +DUP(4) +PUSH([7, 66]) +JUMP +"] + 164 [ color=black shape=rectangle label="Bytecode range: (0x6e2, 0x6eb] +--- +JUMPDEST +SWAP(2) +POP +PUSH([8, 16]) +PUSH([32]) +DUP(5) +ADD +PUSH([7, 66]) +JUMP +"] + 165 [ color=black shape=rectangle label="Bytecode range: (0x6eb, 0x6f4] +--- +JUMPDEST +SWAP(1) +POP +SWAP(3) +POP +SWAP(3) +SWAP(1) +POP +JUMP +"] + 166 [ color=black shape=rectangle label="Bytecode range: (0x6f4, 0x6ff] +--- +JUMPDEST +PUSH([1]) +DUP(2) +DUP(2) +SHR +SWAP(1) +DUP(3) +AND +DUP(1) +PUSH([8, 45]) +JUMPI +"] + 167 [ color=black shape=rectangle label="Bytecode range: (0x6ff, 0x704] +--- +PUSH([127]) +DUP(3) +AND +SWAP(2) +POP +"] + 168 [ color=black shape=rectangle label="Bytecode range: (0x704, 0x70c] +--- +JUMPDEST +PUSH([32]) +DUP(3) +LT +DUP(2) +SUB +PUSH([8, 77]) +JUMPI +"] + 169 [ color=black shape=rectangle label="Bytecode range: (0x70c, 0x717] +--- +PUSH([78, 72, 123, 113]) +PUSH([224]) +SHL +PUSH([0]) +MSTORE +PUSH([34]) +PUSH([4]) +MSTORE +PUSH([36]) +PUSH([0]) +REVERT +"] + 170 [ color=black shape=rectangle label="Bytecode range: (0x717, 0x71d] +--- +JUMPDEST +POP +SWAP(2) +SWAP(1) +POP +JUMP +"] + 171 [ color=black shape=rectangle label="Bytecode range: (0x71d, 0x727] +--- +JUMPDEST +DUP(1) +DUP(3) +ADD +DUP(1) +DUP(3) +GT +ISZERO +PUSH([2, 124]) +JUMPI +"] + 172 [ color=black shape=rectangle label="Bytecode range: (0x727, 0x732] +--- +PUSH([78, 72, 123, 113]) +PUSH([224]) +SHL +PUSH([0]) +MSTORE +PUSH([17]) +PUSH([4]) +MSTORE +PUSH([36]) +PUSH([0]) +REVERT +"] + 0 -> 3 [ style=solid] + 55 -> 57 [ style=solid] + 3 -> 4 [ style=solid] + 4 -> 2 [ style=solid] + 1 -> 5 [ style=dashed] + 54 -> 53 [ style=solid] + 1 -> 6 [ style=dashed] + 53 -> 55 [ style=solid] + 1 -> 7 [ style=dashed] + 51 -> 42 [ style=solid] + 1 -> 8 [ style=dashed] + 49 -> 51 [ style=solid] + 1 -> 9 [ style=dashed] + 9 -> 2 [ style=solid] + 1 -> 10 [ style=dashed] + 48 -> 52 [ style=solid] + 10 -> 11 [ style=solid] + 11 -> 2 [ style=solid] + 1 -> 12 [ style=dashed] + 47 -> 36 [ style=solid] + 12 -> 13 [ style=solid] + 46 -> 31 [ style=solid] + 1 -> 14 [ style=dashed] + 45 -> 9 [ style=solid] + 14 -> 15 [ style=solid] + 44 -> 46 [ style=solid] + 1 -> 16 [ style=dashed] + 41 -> 40 [ style=solid] + 16 -> 17 [ style=solid] + 17 -> 2 [ style=solid] + 1 -> 18 [ style=dashed] + 1 -> 19 [ style=dashed] + 18 -> 19 [ style=solid] + 40 -> 42 [ style=solid] + 19 -> 20 [ style=solid] + 37 -> 39 [ style=solid] + 1 -> 21 [ style=dashed] + 21 -> 1 [ style=dashed] + 1 -> 22 [ style=dashed] + 36 -> 43 [ style=solid] + 22 -> 23 [ style=solid] + 23 -> 2 [ style=solid] + 1 -> 24 [ style=dashed] + 33 -> 35 [ style=solid] + 24 -> 25 [ style=solid] + 25 -> 2 [ style=solid] + 1 -> 26 [ style=dashed] + 31 -> 33 [ style=solid] + 1 -> 27 [ style=dashed] + 29 -> 10 [ style=solid] + 27 -> 28 [ style=solid] + 28 -> 2 [ style=solid] + 1 -> 29 [ style=dashed] + 27 -> 29 [ style=solid] + 1 -> 30 [ style=dashed] + 30 -> 1 [ style=dashed] + 1 -> 31 [ style=dashed] + 26 -> 10 [ style=solid] + 31 -> 32 [ style=solid] + 1 -> 33 [ style=dashed] + 32 -> 33 [ style=solid] + 24 -> 26 [ style=solid] + 33 -> 34 [ style=solid] + 34 -> 2 [ style=solid] + 1 -> 35 [ style=dashed] + 35 -> 1 [ style=dashed] + 1 -> 36 [ style=dashed] + 22 -> 24 [ style=solid] + 36 -> 37 [ style=solid] + 20 -> 19 [ style=solid] + 37 -> 38 [ style=solid] + 1 -> 39 [ style=dashed] + 38 -> 39 [ style=solid] + 1 -> 40 [ style=dashed] + 39 -> 40 [ style=solid] + 19 -> 21 [ style=solid] + 40 -> 41 [ style=solid] + 16 -> 18 [ style=solid] + 1 -> 42 [ style=dashed] + 1 -> 43 [ style=dashed] + 42 -> 43 [ style=solid] + 43 -> 1 [ style=dashed] + 1 -> 44 [ style=dashed] + 15 -> 9 [ style=solid] + 44 -> 45 [ style=solid] + 14 -> 16 [ style=solid] + 1 -> 46 [ style=dashed] + 13 -> 9 [ style=solid] + 1 -> 47 [ style=dashed] + 12 -> 14 [ style=solid] + 1 -> 48 [ style=dashed] + 10 -> 12 [ style=solid] + 48 -> 49 [ style=solid] + 8 -> 58 [ style=solid] + 49 -> 50 [ style=solid] + 1 -> 51 [ style=dashed] + 50 -> 51 [ style=solid] + 7 -> 44 [ style=solid] + 1 -> 52 [ style=dashed] + 1 -> 53 [ style=dashed] + 52 -> 53 [ style=solid] + 6 -> 44 [ style=solid] + 53 -> 54 [ style=solid] + 5 -> 22 [ style=solid] + 1 -> 55 [ style=dashed] + 3 -> 5 [ style=solid] + 55 -> 56 [ style=solid] + 1 -> 57 [ style=dashed] + 56 -> 57 [ style=solid] + 57 -> 1 [ style=dashed] + 1 -> 58 [ style=dashed] + 58 -> 2 [ style=solid] + 1 -> 62 [ style=dashed] + 62 -> 1 [ style=dashed] + 62 -> 63 [ style=solid] + 63 -> 1 [ style=dashed] + 63 -> 64 [ style=solid] + 64 -> 1 [ style=dashed] + 64 -> 65 [ style=solid] + 65 -> 1 [ style=dashed] + 65 -> 66 [ style=solid] + 66 -> 1 [ style=dashed] + 66 -> 67 [ style=solid] + 67 -> 1 [ style=dashed] + 67 -> 68 [ style=solid] + 68 -> 2 [ style=solid] + 1 -> 69 [ style=dashed] + 69 -> 1 [ style=dashed] + 69 -> 70 [ style=solid] + 70 -> 1 [ style=dashed] + 70 -> 71 [ style=solid] + 71 -> 1 [ style=dashed] + 71 -> 72 [ style=solid] + 72 -> 2 [ style=solid] + 1 -> 73 [ style=dashed] + 73 -> 1 [ style=dashed] + 73 -> 74 [ style=solid] + 74 -> 1 [ style=dashed] + 74 -> 75 [ style=solid] + 75 -> 1 [ style=dashed] + 75 -> 76 [ style=solid] + 76 -> 1 [ style=dashed] + 76 -> 77 [ style=solid] + 77 -> 1 [ style=dashed] + 77 -> 78 [ style=solid] + 1 -> 78 [ style=dashed] + 78 -> 2 [ style=solid] + 1 -> 79 [ style=dashed] + 79 -> 1 [ style=dashed] + 1 -> 80 [ style=dashed] + 80 -> 1 [ style=dashed] + 1 -> 81 [ style=dashed] + 81 -> 2 [ style=solid] + 1 -> 82 [ style=dashed] + 82 -> 1 [ style=dashed] + 1 -> 83 [ style=dashed] + 83 -> 1 [ style=dashed] + 1 -> 84 [ style=dashed] + 84 -> 1 [ style=dashed] + 1 -> 85 [ style=dashed] + 1 -> 86 [ style=dashed] + 85 -> 86 [ style=solid] + 86 -> 1 [ style=dashed] + 1 -> 87 [ style=dashed] + 87 -> 1 [ style=dashed] + 1 -> 88 [ style=dashed] + 88 -> 1 [ style=dashed] + 1 -> 89 [ style=dashed] + 89 -> 1 [ style=dashed] + 1 -> 90 [ style=dashed] + 90 -> 1 [ style=dashed] + 1 -> 91 [ style=dashed] + 91 -> 1 [ style=dashed] + 1 -> 92 [ style=dashed] + 92 -> 1 [ style=dashed] + 1 -> 93 [ style=dashed] + 93 -> 1 [ style=dashed] + 1 -> 94 [ style=dashed] + 94 -> 1 [ style=dashed] + 1 -> 95 [ style=dashed] + 95 -> 1 [ style=dashed] + 1 -> 96 [ style=dashed] + 96 -> 1 [ style=dashed] + 1 -> 97 [ style=dashed] + 97 -> 1 [ style=dashed] + 1 -> 98 [ style=dashed] + 98 -> 1 [ style=dashed] + 1 -> 99 [ style=dashed] + 99 -> 1 [ style=dashed] + 1 -> 100 [ style=dashed] + 100 -> 1 [ style=dashed] + 1 -> 101 [ style=dashed] + 101 -> 1 [ style=dashed] + 1 -> 102 [ style=dashed] + 102 -> 1 [ style=dashed] + 1 -> 103 [ style=dashed] + 103 -> 1 [ style=dashed] + 103 -> 104 [ style=solid] + 104 -> 1 [ style=dashed] + 104 -> 105 [ style=solid] + 105 -> 1 [ style=dashed] + 1 -> 106 [ style=dashed] + 1 -> 107 [ style=dashed] + 106 -> 107 [ style=solid] + 107 -> 1 [ style=dashed] + 107 -> 108 [ style=solid] + 1 -> 109 [ style=dashed] + 108 -> 109 [ style=solid] + 109 -> 1 [ style=dashed] + 1 -> 110 [ style=dashed] + 110 -> 1 [ style=dashed] + 1 -> 111 [ style=dashed] + 1 -> 112 [ style=dashed] + 111 -> 112 [ style=solid] + 112 -> 1 [ style=dashed] + 1 -> 113 [ style=dashed] + 113 -> 1 [ style=dashed] + 1 -> 114 [ style=dashed] + 114 -> 1 [ style=dashed] + 1 -> 115 [ style=dashed] + 115 -> 1 [ style=dashed] + 1 -> 116 [ style=dashed] + 116 -> 1 [ style=dashed] + 1 -> 117 [ style=dashed] + 117 -> 1 [ style=dashed] + 1 -> 118 [ style=dashed] + 118 -> 1 [ style=dashed] + 1 -> 119 [ style=dashed] + 119 -> 1 [ style=dashed] + 119 -> 120 [ style=solid] + 1 -> 121 [ style=dashed] + 120 -> 121 [ style=solid] + 121 -> 2 [ style=solid] + 1 -> 122 [ style=dashed] + 122 -> 1 [ style=dashed] + 1 -> 123 [ style=dashed] + 123 -> 1 [ style=dashed] + 1 -> 124 [ style=dashed] + 124 -> 1 [ style=dashed] + 124 -> 125 [ style=solid] + 125 -> 1 [ style=dashed] + 1 -> 126 [ style=dashed] + 126 -> 1 [ style=dashed] + 126 -> 127 [ style=solid] + 127 -> 1 [ style=dashed] + 1 -> 128 [ style=dashed] + 128 -> 1 [ style=dashed] + 1 -> 129 [ style=dashed] + 129 -> 1 [ style=dashed] + 129 -> 130 [ style=solid] + 130 -> 1 [ style=dashed] + 130 -> 131 [ style=solid] + 131 -> 1 [ style=dashed] + 1 -> 132 [ style=dashed] + 132 -> 1 [ style=dashed] + 1 -> 133 [ style=dashed] + 133 -> 1 [ style=dashed] + 1 -> 134 [ style=dashed] + 134 -> 1 [ style=dashed] + 134 -> 135 [ style=solid] + 135 -> 1 [ style=dashed] + 1 -> 136 [ style=dashed] + 136 -> 1 [ style=dashed] + 136 -> 137 [ style=solid] + 137 -> 1 [ style=dashed] + 1 -> 138 [ style=dashed] + 138 -> 1 [ style=dashed] + 138 -> 139 [ style=solid] + 139 -> 1 [ style=dashed] + 1 -> 140 [ style=dashed] + 140 -> 1 [ style=dashed] + 1 -> 141 [ style=dashed] + 1 -> 142 [ style=dashed] + 141 -> 142 [ style=solid] + 142 -> 1 [ style=dashed] + 142 -> 143 [ style=solid] + 143 -> 1 [ style=dashed] + 1 -> 144 [ style=dashed] + 144 -> 1 [ style=dashed] + 1 -> 145 [ style=dashed] + 145 -> 1 [ style=dashed] + 145 -> 146 [ style=solid] + 146 -> 2 [ style=solid] + 1 -> 147 [ style=dashed] + 147 -> 1 [ style=dashed] + 1 -> 148 [ style=dashed] + 148 -> 1 [ style=dashed] + 148 -> 149 [ style=solid] + 149 -> 2 [ style=solid] + 1 -> 150 [ style=dashed] + 150 -> 1 [ style=dashed] + 1 -> 151 [ style=dashed] + 151 -> 1 [ style=dashed] + 1 -> 152 [ style=dashed] + 152 -> 1 [ style=dashed] + 152 -> 153 [ style=solid] + 153 -> 2 [ style=solid] + 1 -> 154 [ style=dashed] + 154 -> 1 [ style=dashed] + 1 -> 155 [ style=dashed] + 155 -> 1 [ style=dashed] + 1 -> 156 [ style=dashed] + 156 -> 1 [ style=dashed] + 1 -> 157 [ style=dashed] + 157 -> 1 [ style=dashed] + 157 -> 158 [ style=solid] + 158 -> 2 [ style=solid] + 1 -> 159 [ style=dashed] + 159 -> 1 [ style=dashed] + 1 -> 160 [ style=dashed] + 160 -> 1 [ style=dashed] + 1 -> 161 [ style=dashed] + 161 -> 1 [ style=dashed] + 161 -> 162 [ style=solid] + 162 -> 2 [ style=solid] + 1 -> 163 [ style=dashed] + 163 -> 1 [ style=dashed] + 1 -> 164 [ style=dashed] + 164 -> 1 [ style=dashed] + 1 -> 165 [ style=dashed] + 165 -> 1 [ style=dashed] + 1 -> 166 [ style=dashed] + 166 -> 1 [ style=dashed] + 166 -> 167 [ style=solid] + 1 -> 168 [ style=dashed] + 167 -> 168 [ style=solid] + 168 -> 1 [ style=dashed] + 168 -> 169 [ style=solid] + 169 -> 2 [ style=solid] + 1 -> 170 [ style=dashed] + 170 -> 1 [ style=dashed] + 1 -> 171 [ style=dashed] + 171 -> 1 [ style=dashed] + 171 -> 172 [ style=solid] + 172 -> 2 [ style=solid] +} + diff --git a/testdata/empty.bin b/testdata/empty.bin new file mode 100644 index 0000000..e69de29 diff --git a/testdata/empty_contract_payable_initcode.bin b/testdata/empty_contract_payable_initcode.bin new file mode 100644 index 0000000..cd42cfa --- /dev/null +++ b/testdata/empty_contract_payable_initcode.bin @@ -0,0 +1 @@ +6080604052348015600f57600080fd5b50606180601d6000396000f3fe608060405260043610601c5760003560e01c8063c2985578146021575b600080fd5b60276029565b005b56fea2646970667358221220493add52a9d6686c38a8a20786dbed15474f43c23a0d7c3ab1f57988f13aa10664736f6c63430008170033 diff --git a/testdata/erc20_old.bin b/testdata/erc20_paris.bin similarity index 100% rename from testdata/erc20_old.bin rename to testdata/erc20_paris.bin diff --git a/testdata/fibonacci.evm b/testdata/fibonacci.evm deleted file mode 100644 index b1d9dc7..0000000 --- a/testdata/fibonacci.evm +++ /dev/null @@ -1 +0,0 @@ -600035600160009160025b818111601c576001019180930191600a565b505060005260206000f350 diff --git a/testdata/immutable.bin b/testdata/immutable.bin new file mode 100644 index 0000000..1ce446c --- /dev/null +++ b/testdata/immutable.bin @@ -0,0 +1 @@ +60a0604052348015600f57600080fd5b506040516100ef3803806100ef8339818101604052810190602f91906072565b806080818152505050609a565b600080fd5b6000819050919050565b6052816041565b8114605c57600080fd5b50565b600081519050606c81604b565b92915050565b6000602082840312156085576084603c565b5b6000609184828501605f565b91505092915050565b608051603f6100b060003960005050603f6000f3fe6080604052600080fdfea26469706673582212207fa219f468d46a3e6f8235806d69ac4511b9f86f1459e1e01d108b9e701b902764736f6c63430008170033 diff --git a/testdata/mimc_83584f83f26aF4eDDA9CBe8C730bc87C364b28fe.bin b/testdata/mimc_83584f83f26aF4eDDA9CBe8C730bc87C364b28fe.bin new file mode 100644 index 0000000..069208f --- /dev/null +++ b/testdata/mimc_83584f83f26aF4eDDA9CBe8C730bc87C364b28fe.bin @@ -0,0 +1 @@ +606460006000377c01000000000000000000000000000000000000000000000000000000006000510463f47d33b5146200003557fe5b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016004518160245181838180828009800909089082827f0fbe43c36a80e36d7c7c584d4f8f3759fb51f0d66065d8a227b688d12488c5d408839081808280098009098391089082827f9c48cd3e00a6195a253fc009e60f249456f802ff9baf6549210d201321efc1cc08839081808280098009098391089082827f27c0849dba2643077c13eb42ffb97663cdcecd669bf10f756be30bab71b86cf808839081808280098009098391089082827f2bf76744736132e5c68f7dfdd5b792681d415098554fd8280f00d11b172b80d208839081808280098009098391089082827f33133eb4a1a1ab45037c8bdf9adbb2999baf06f20a9c95180dc4ccdcbec5856808839081808280098009098391089082827f588bb66012356dbc9b059ef1d792b563d6c18624dddecc3fe4583fd3551e9b3008839081808280098009098391089082827f71bc3e244e1b92911fe7f53cf523e491fd6ff487d59337a1d92f92668c4f4c3608839081808280098009098391089082827fd1808e2b039fd010c489768f78d7499938ccc0858f3295151787cfe8b7e40be108839081808280098009098391089082827f76978af3ded437cf41b3faa40cd6bcfce94f27f4abcc3ed34be19abd2c4537d008839081808280098009098391089082827f0a9baee798a320b0ca5b1cf888386d1dc12c13b38e10225aa4e9f03069a099f508839081808280098009098391089082827fb79dbf6050a03b16c3ade8d77e11c767d2251af9cdbd6cdf9a8a0ee921b32c7908839081808280098009098391089082827fa74bbcf5067f067faec2cce4b98d130d7927456f5c5f6c00e0f5406a24eb8b1908839081808280098009098391089082827fab7ab080d4c4018bda6ecc8bd67468bc4619ba12f25b0da879a639c758c8855d08839081808280098009098391089082827fe6a5b797c2bba7e9a873b37f5c41adc47765e9be4a1f0e0650e6a24ad226876308839081808280098009098391089082827f6270ae87cf3d82cf9c0b5f428466c429d7b7cbe234cecff39969171af006016c08839081808280098009098391089082827f9951c9f6e76d636b52f7600d979ca9f3b643dfbe9551c83b31542830321b2a6608839081808280098009098391089082827f4119469e44229cc40c4ff555a2b6f6b39961088e741e3c20a3c9b47f130c555008839081808280098009098391089082827f5d795e02bbaf90ff1f384741e5f18f8b644a0080441315d0e5b3c8123452a0b008839081808280098009098391089082827f281e90a515e6409e9177b4f297f8049ce3d4c3659423c48b3fd64e83596ff10108839081808280098009098391089082827f424185c60a21e84970f7d32cacaa2725aa8a844caea7ed760d2b965af1bf3e7d08839081808280098009098391089082827fd96fcbc3960614ea887da609187a5dada2e1b829f23309a6375212cea1f25c0908839081808280098009098391089082827ffde84026d7c294300af18f7712fc3662f43387ae8cf7fdda1f9a810f4b24bcf208839081808280098009098391089082827f3a9d568575846aa6b8a890b3c237fd0447426db878e6e25333b8eb9b386195c108839081808280098009098391089082827f55a2aa32c84a4cae196dd4094b685dd11757470a3be094d98eea73f02452aa3608839081808280098009098391089082827fcbc9481380978d29ebc5b0a8d4481cd2ef654ee800907adb3d38dc2fd9265fab08839081808280098009098391089082827f24e53af71ef06bacb76d3294c11223911e9d177ff09b7009febc484add0beb7408839081808280098009098391089082827fdbd44e16108225766dac3e5fe7acbe9df519bbba97380e5e9437a90658f2139308839081808280098009098391089082827fc6f434863c79013bb2c202331e04bccea2251c1ff6f191dc2afa23e6f6d28e4e08839081808280098009098391089082827f3490eeb39a733c0e8062d87f981ae65a8fccf25c448f4455d27db3915351b06608839081808280098009098391089082827f30b89830ff7ade3558a5361a24869130ce1fcce97211602962e34859525dac4f08839081808280098009098391089082827f29bae21b579d080a75c1694da628d0ecfd83efc9c8468704f410300062f64ca908839081808280098009098391089082827fe326499de0476e719915dd1c661ef4550723d4aee9ee9af224edd208790fce4408839081808280098009098391089082827f8c45208b8baa6f473821415957088c0b7e72a465f460b09ece2d270aee2f184108839081808280098009098391089082827ffe2ad454f451348f26ce2cc7e7914aef3eb96e8f89a4619a1dc7d11f8401c35208839081808280098009098391089082827f0929db368ef2af2d29bca38845325b0b7a820a4889e44b5829bbe1ed47fd4d5208839081808280098009098391089082827f16531d424b0cbaf9abbf2d2acde698462ea4555bf32ccf1bbd26697e905066f608839081808280098009098391089082827ff5c30d247f045ff6d05cf0dd0a49c9823e7a24b0d751d3c721353b96f29d76f608839081808280098009098391089082827f6eb7a3614056c230c6f171370fdd9d1048bb00b2cdd1b2721d11bdda5023f48608839081808280098009098391089082827f0ee9c4621642a272f710908707557498d25a6fdd51866da5d9f0d205355a618908839081808280098009098391089082827f78ca1cb1c7f6c6894d1cf94f327b8763be173151b6b06f99dfc6a944bb5a72f008839081808280098009098391089082827f5d24d0b1b304d05311ce0f274b0d93746a4860ed5cdd8d4348de557ea7a5ee7a08839081808280098009098391089082827f77423dabd1a3cddc8691438fc5891e3fd49ac0f3e21aaf249791bfde1303d2f308839081808280098009098391089082827f0642e8800a48cc04c0168232c6f542396597a67cf395ad622d947e98bb68697a08839081808280098009098391089082827fc1e7d3cbbc4c35b7490647d8402e56d334336943bda91fe2d34ca9727c0e3df508839081808280098009098391089082827f8d6fb1730335204f38f85e408ac861e76f24349ab6ee0469c22e19350bb24fe108839081808280098009098391089082827f67d0faf5f0db32a1b60e13dc4914246b9edac7990fb4990b19aa86815586441a08839081808280098009098391089082827f2605b9b909ded1b04971eae979027c4e0de57f3b6a60d5ed58aba619c34749ce08839081808280098009098391089082827fd276890b2c205db85f000d1f5111ed8f177e279cae3e52862780f04e846228d008839081808280098009098391089082827f2ac5905f9450a21ef6905ed5951a91b3730e3a2e2d62b50bdeb810015d50376b08839081808280098009098391089082827f7a366839f0291ca54da674ac3f0e1e9aa8b687ba533926cb40268039e57b967a08839081808280098009098391089082827f67ab0f3466989c3dbbe209c37ec272ba83984ba6e445be6d472b63e3ca7270e308839081808280098009098391089082827f0e786007d0ce7e28a90e31d3263887d40c556dec88fcb8b56bc9e9c05ecc0c2908839081808280098009098391089082827f0b814ed99bd00eca389b0022663dbfddfbfa15e321c19abcf1eaf9556075fb6808839081808280098009098391089082827f65c0321ba26fcee4fdc35b4999b78ceb54dcaf9fec2e3bdea98e9f82925c093208839081808280098009098391089082827fab2d2a929601f9c3520e0b14aaa6ba9f1e79821a5b768919670a4ea970722bf408839081808280098009098391089082827fcdd2e0744d4af1a81918de69ec12128a5871367303ff83ed764771cbbdf6502308839081808280098009098391089082827f74527d0c0868f2ec628086b874fa66a7347d3d3b918d2e07a5f33e1067e8ac5808839081808280098009098391089082827f1c6bf6ac0314caead23e357bfcbbaa17d670672ae3a475f80934c716f10aca2508839081808280098009098391089082827f3c4007e286f8dc7efd5d0eeb0e95d7aa6589361d128a0cccb17b554c851a643208839081808280098009098391089082827fae468a86a5a7db7c763a053eb09ac1a02809ce095258c88101ee319e12b0697e08839081808280098009098391089082827f9333e3d052b7c77fcac1eb366f610f6f97852242b1317a87b80f3bbc5c8c2d1d08839081808280098009098391089082827f52ec1d675cf5353153f6b628414783ca6b7fc0fe01948ca206daad712296e39508839081808280098009098391089082827f13ceeeb301572b4991076750e11ea7e7fcbfee454d90dc1763989004a1894f9308839081808280098009098391089082827f8505737e7e94939a08d8cda10b6fbbbf879b2141ae7eabc30fcd22405135fe6408839081808280098009098391089082827f6127db7ac5200a212092b66ec2bfc63653f4dc8ac66c76008fef885258a258b508839081808280098009098391089082827f12692a7d808f44e31d628dbcfea377eb073fb918d7beb8136ea47f8cf094c88c08839081808280098009098391089082827f260e384b1268e3a347c91d6987fd280fa0a275541a7c5be34bf126af35c962e008839081808280098009098391089082827fd88c3b01966d90e713aee8d482ceaa6925311d2342e1a5aca4fcd2f44b6daddc08839081808280098009098391089082827fb87e868affd91b078a87fa75ac9332a6cf23587d94e20c3262db5e91f30bf04b08839081808280098009098391089082827fb5ba5f8acad1a950a3bbf2201055cd3ea27056c0c53f0c4c97f33cda8dbfe90908839081808280098009098391089082827f59ca814b49e00d7b3118c53a2986ded128584acd7428735e08ade6661c457f7508839081808280098009098391089082827f0fc4c0bea813a223fd510c07f7bbe337badd4bcf28649a0d378970c2a15b3aa508839081808280098009098391089082827f0053f1ea6dd60e7a6db09a00be77549ff3d4ee3737be7fb42052ae1321f667c308839081808280098009098391089082827feb937077bb10c8fe38716d4e38edc1f9e7b18c6414fef85fe7e9c5567baa4a0408839081808280098009098391089082827fbacb14c0f1508d828f7fd048d716b8044aec7f0fb48e85e717bf532db972520708839081808280098009098391089082827f4ca0abb8beb7cff572a0c1e6f58e080e1bb243d497a3e74538442a4555ad40be08839081808280098009098391089082827fda9eefd411e590d7e44592cce298af87b2c62aa3cc8bb137aa99ca8d4aa551b508839081808280098009098391089082827f153dae43cef763e7a2fc9846f09a2973b0ad9c35894c220699bcc2954501c6bd08839081808280098009098391089082827fd4ed2a09375813b4fb504c7a9ba13110bdd8549a47349db82c15a434c090e87b08839081808280098009098391089082827f0063a5c4c9c12dcf4bae72c69f3a225664469503d61d9eae5d9553bfb006095b08839081808280098009098391089082827fdc8a4d35ad28e59dd3713b45985cd3b70e37ccc2be42086f1ea078fe2dc9d82d08839081808280098009098391089082827f486ba219308f0c847b22fcb4449f8855192536c01b8057904e81c1c7814f483b08839081808280098009098391089082827f34d9604140a1ac9fdb204285b9fe1b303c281af2fc5fb362f6577282b423bcf308839081808280098009098391089082827fc1681959ec4bc3656911db2b2f56aa4db709c26f1a0a25c879286e37f437465d08839081808280098009098391089082827ffcd849f3b5f9e4368af75619fb27f2e335adbb9b44988f17c4d389fa751ad47a08839081808280098009098391089082827ff5f7fc22ad64c8e7c1e005110e13f4f1c6b1f8f8cc59000db0e3bb38f99554a508839081808280098009098391089082827fa9133b8a20fbae4633ec5f82cb47a38ae1877d12d1febb23982c7c808aa5317508839081808280098009098391089082827ff4827c5c7b61141cc31b75984bb3ed16ed579e5b72e32a1289b63ab55eaf8c1208839081808280098009098391089082827fcca361819ffefe3e50fe34c91a322c9405f4e5a168c1fc0a0a1883993e32c9f408839081808280098009098391089082827f6656088842bfc9e325a532784d3362cecfa86f9c7b208a6b499836ebe48ff15708839081808280098009098391089082827f00129c7cd00e42ed05a37dbceb80d47b65e1d750ef2148278a54723fdf42c4cc08839081808280098009098391089082827fa85b235631b786f85cd46f7768f6c71ae004ad267ae59bdf929ada149b19588808839081808280098009098391089082827f34df65a82686be09c5b237911abf237a9887c1a418f279ac79b446d7d311f5ea08839081808280098009098391089082827f815a850c3989df9ca6231e0bdd9916fc0e076f2c6c7f0f260a846d0179f9c32d08839081808280098009098391089082827f50fb0940848a67aee83d348421fadd79aefc7a2adabeec6e64904ebe1bf63e7d08839081808280098009098391089082827fbab63a16273599f8b66895461e62a19ff0d103693be771d93e3691bba89cdd8d08839081808280098009098391089082827f6931a091756e0bc709ebecfffba5038634c5b3d5d0c5876dd72aac67452db8a208839081808280098009098391089082827f55559b8bb79db8809c46ee627f1b5ce1d8e6d89bf94a9987a1407759d1ba896308839081808280098009098391089082827fa9a1a11b2979018cb155914d09f1df19b7ffec241e8b2487b6f6272a56a44a0a08839081808280098009098391089082827ff83293400e7bccea4bb86dcb0d5ca57fa2466e13a572d7d3531c6fa491cb0f1b08839081808280098009098391089082827fb7cb5742b6bc5339624d3568a33c21f31b877f8396972582028da999abf249f208839081808280098009098391089082827ff56efb400f8500b5c5bf811c65c86c7ed2e965f14f1a69bca436c0c60b79f46508839081808280098009098391089082827fd7c4427998d9c440f849dcd75b7157996eaad1b9a1d58cc2441931300e26eb2208839081808280098009098391089082827fca5ed18ad53e33fdc3ae8cf353ff3f6dd315f60060442b74f6b614b24ebd4cc308839081808280098009098391089082827f9ad3e9376c97b194a0fbf43e22a3616981d777365c765ead09a1d033fdf536b708839081808280098009098391089082827fc6daeff5769a06b26fe3b8fef30df07b1387373a7814cef364fe1d6059eaf54a08839081808280098009098391089082827fc20a78398345c6b8cf439643dab96223bf879c302648293eaf496fee5c978c6608839081808280098009098391089082827f589ca65b6cf0e90653c06dddc057dc61ba2839974569051c98b43e8618716efb08839081808280098009098391089082827f83064161f127d8c59fc73625957e21630dc6dc99e5443f6ce37ecd6bf28e69b708839081808280098009098391089082827f46d0ba662b50100b9a3af52052f68932feec1d12290b2033c4f49148893d8ba308839081808280098009098391089082827f18dd55b4a83a53f2ee578eb3e6d26f594824d44670fc3f4de80642344d15c09a08839081808280098009098391089082827f9fb5b594f48bc58b345ab90ded705920a7274b8e070eee8ce8cf90c72c3604b608839081808280098009098391089082827f1901d8f4f2c8449128e00663978f2050f2eb1cd6acb60d9d09c57c5d46ee54fe08839081808280098009098391089082827f5ec56789beab24ef7ee32f594d5fc561ec59dfeb93606dc7dcc6fe65133a7db408839081808280098009098391089082827f01c0b2cbe4fa9877a3d08eb67c510e8630da0a8beda94a6d9283e6f70d268bc508839081808280098009098391089082827f0b1d85acd9031a9107350eed946a25734e974799c5ba7cff13b15a5a623a25f008839081808280098009098391089082827f204497d1d359552905a2fe655f3d6f94926ea92d12cdaa6556ec26362f239f6408839081808280098009098391089082827fe075f7edc6631a8d7ffe33019f44fc91f286236d5a5f90f16de4791b72a2a5f008839081808280098009098391089082827f243f46e353354256ab8fe0ca4e9230dfc330bc163e602dfeaf307c1d1a7264b908839081808280098009098391089082827fd448ae5e09625fa1fcfd732fc9cd8f06e4c33b81f0a9240c83da56f41e9ecceb08839081808280098009098391089082827f2f312eef69a33d9fa753c08840275692a03432b3e6da67f9c59b9f9f4971cd5608839081808280098009098391089082827f5f333996af231bd5a293137da91801e191a6f24eb532ad1a7e6e9a2ad0efbc0008839081808280098009098391089082827fa8f771e0383a832dc8e2eaa8efabda300947acaf0684fabddf8b4abb0abd8a6208839081808280098009098391089082827f9ff0b3d7a4643596f651b70c1963cc4fa6c46018d78f05cb2c5f187e25df83a908839081808280098009098391089082827f9c373b704838325648273734dcdf962d7c156f431f70380ba4855832c4a238b808839081808280098009098391089082827fea2afa02604b8afeeb570f48a0e97a5e6bfe9613394b9a6b0026ecd6cec8c33a08839081808280098009098391089082827f68892258cd8eb43b71caa6d6837ec9959bfdfd72f25c9005ebaffc4011f8a7bf08839081808280098009098391089082827ff2824f561f6f82e3c1232836b0d268fa3b1b5489edd39a5fe1503bfc7ca91f4908839081808280098009098391089082827f164eda75fda2861f9d812f24e37ac938844fbe383c243b32b9f66ae2e76be71908839081808280098009098391089082827ff0a6fc431f5bf0dd1cca93b8b65b3f72c91f0693e2c74be9243b15abb31afcc008839081808280098009098391089082827fe68db66ba891ef0cd527f09ec6fff3ec0a269cf3d891a35ec13c902f70334b4f08839081808280098009098391089082827f3a44a5b102f7883a2b8630a3cae6e6db2e6e483bb7cfeb3492cbd91793ef598e08839081808280098009098391089082827f43939fe8ef789acb33cbf129ba8a3aa1bd61510a178022a05177c9c5a1c59bf108839081808280098009098391089082827f936fe3b66dfda1bc5a7aae241b4db442858bd720c1d579c0c869f273cd55d77408839081808280098009098391089082827f3490fcaa8ffa37f35dc67ae006e81352c7103945417b8e4b142afcaefa344b8508839081808280098009098391089082827fcae66096cff344caca53ffe0e58aafeb468bd174f00d8abc425b2099c088187408839081808280098009098391089082827fc7d05783a41bc14f3c9a45384b6d5e2547c5b6a224c8316910b208f2718a70ab08839081808280098009098391089082827f5ac6b9ba94040d5692b865b6677b60ef3201b5c2121699f70beb9f9b2528a02608839081808280098009098391089082827fa902a3d4d9ecbfb9b2c76fddf780554bf93cad97b244e805d3adb94e1816290008839081808280098009098391089082827fe9df91ffeeb086a4d26041c29dac6fca1d56a4d022fe34b38831267395b98d2708839081808280098009098391089082827f862646f851d91a8840ad9ee711f12ec13b3e8f980ff5ef5ee43ca4520d57def708839081808280098009098391089082827f30b7381c9725b9db07816baf8524943a79cea135807c84cce0833485c11e0c2e08839081808280098009098391089082827f96afc10c5cedaddbda99df79387397c9be74a5b50f3a0c04ccb68d4e0f3a989f08839081808280098009098391089082827f3543da80d10da251c548776fe907c4ef89993d62e0062ae5c0496fcb851c366108839081808280098009098391089082827fe5140fe26d8b008430fccd50a68e3e11c1163d63b6d8b7cc40bc6f3c1d0b1b0608839081808280098009098391089082827ffefdf1872e4475e8bbb0ef6fab7f561bff121314695c433bd4c29ec118060c9608839081808280098009098391089082827f6bb8c9f3d57b18e002df059db1e6a5d42ad566f153f18460774f68ac2650940008839081808280098009098391089082827f5415122d50b26f4fab5784004c56cf03f128f825ad2236f4b3d51f74737bd97308839081808280098009098391089082827f00e115c4a98efae6a3a5ecc873b0cef63ccd5b515710a3ab03ec52218f784dc908839081808280098009098391089082827fda7d525427bad87b88238657c21331245578bc76aa6240b7f972382537a202ab08839081808280098009098391089082827f83332e8b34505b83010270dc795290a2f515b8f89c163acecdf4799df04c62f808839081808280098009098391089082827fb09ecb6033d1a065f17a61066cd737d0c3c5873b51c3ab0a285e26939e62aa1808839081808280098009098391089082827f24e65c718938c2b937378e7435332174329730bde85a4185e37875824eb4985908839081808280098009098391089082827f68e41430ccd41cc5e92a9f9acd2e955c1385b9f5ed8d3f133d767429484a8eba08839081808280098009098391089082827fc038fe9d0125ab8be54545276f841274e414c596ed4c9eaa6919604603d1ffa908839081808280098009098391089082827f23248698612cd8e83234fcf5db9b6b225f4b0ba78d72ef13ea1edff5f0fb029808839081808280098009098391089082827fd2a9fa3d39c1ba91eefa666a1db71c6e0e4e3b707626b0197a4e59e7110cf0d408839081808280098009098391089082827fc28931ee7dfa02b62872e0d937ba3dc5c637118273a1f1f0c4fc880905c82efc08839081808280098009098391089082827f01cd399556445e3d7b201d6c5e56a5794e60be2cfd9a4643e7ead79bb4f60f7908839081808280098009098391089082827fac855cc58d5fbb0dff91a79683eb0e914c1b7d8d0a540d416838a89f83a8312f08839081808280098009098391089082827ff7798af7ccf36b836705849f7dd40328bf9346657255b431446ec75a6817181608839081808280098009098391089082827fe52a24c92d3f067bf551eeaf98c62ba525e84882d7adad835fad8de72986b2b108839081808280098009098391089082827fffc8682759a2bf1dd67c87a77c285467801f1c44fd78fa4eb5957a4832c9d72d08839081808280098009098391089082827f1482ac3e7e4f321627850d95a13942aea6d2923402b913046856ff7e8aaf9aff08839081808280098009098391089082827f17332b4c7aac2a07ccfe954de7ad22ccf6fcb4c5fa15c130ed22a40ae9398f4708839081808280098009098391089082827fd4be0546013f84a0d1e118b37589723b58e323983263616d1b036f8b3fdd858308839081808280098009098391089082827fa64ec737d31dddf939b184438ccdd3e1d3e667572857cd6c9c31a0d1d9b7b08508839081808280098009098391089082827f8ad12fbc74117cff4743d674539c86548c6758710a07a6abe3715e4b53526d3408839081808280098009098391089082827f15a16435a2300b27a337561401f06682ba85019aa0af61b264a1177d38b5c13c08839081808280098009098391089082827f22616f306e76352293a22ab6ee15509d9b108d4136b32fa7f9ed259793f392a108839081808280098009098391089082827f519727b25560caf00ce0d3f911bd4356f907160ab5186da10a629c7ccae1851e08839081808280098009098391089082827fcff39e77928ce9310118d50e29bc87e7f78b53ad51366359aa17f07902ae639208839081808280098009098391089082827f17dead3bfa1968c744118023dead77cdbee22c5b7c2414f5a6bdf82fd94cf3ad08839081808280098009098391089082827f2bef0f8b22a1cfb90100f4a552a9d02b772130123de8144a00c4d57497e1d7f408839081808280098009098391089082827fbf5188713fef90b31c35243f92cfa4331ab076e30e24b355c79b01f41d152a1108839081808280098009098391089082827f3baadd2fd92e3e12fb371be0578941dc0a108fbca0a7d81b88316fb94d6b4dfe08839081808280098009098391089082827fd4f955742e20a28d38611bf9fc4a478c97b673a7cd40d0113a58a1efe338d9aa08839081808280098009098391089082827f3c1c3fe9a5f7ccd54ad5a51a224b3f94775266d19c3733017e4920d7391ad64508839081808280098009098391089082827f6372df6148abeed66fda5461779a9651130c6c525df733852bcd929016768a7a08839081808280098009098391089082827f6d098e848fb853f95adb5a6364b5ab33c79fb08877f2cf3e0e160d9fcb3ebcc508839081808280098009098391089082827f48c5fc90f27431fabfe496dfba14bb0dba71141eb5472a365fd13023f4fe629608839081808280098009098391089082827fbb988dfc0c4dfe53999bd34840adcb63fdbf501ccd622ca2ddf5064ad8cdebf408839081808280098009098391089082827f25b068c942724c424ed5851c9575c22752c9bd25f91ebfa589de3d88ee7627f908839081808280098009098391089082827fed98a1931e361add218de11ff7879bd7114cda19c24ddbe15b3b0190ce01e1aa08839081808280098009098391089082827fc80b5a7d63f6c43542ad612023d3ffd6c684ce2eab837180addcb4decf51854408839081808280098009098391089082827fe2ef24bf47c5203118c6ff96657dd3c6fdff7212d5c798d826455de77b4b70cd08839081808280098009098391089082827f907da812fd5a8375587e4860f87691d0a8d61d454c507d09e5562e1a5d0fcc7608839081808280098009098391089082827fc459abbc62bc6070cacdff597e97990de56edc51cc6643afb0f6789fef1bad6308839081808280098009098391089082827f38d61f5e566855d70d36ef0f0f1fefcd7c829bdd60d95e0ef1fb5b98856280a408839081808280098009098391089082827f13218626665c420d3aa2b0fa49224a3dce8e08b8b56f8851bd9cb5e25cb3042d08839081808280098009098391089082827f6f685fb152dba21b4d02422e237e246df73d7d711ae6d7d33983bae0f873e31008839081808280098009098391089082827f5ade34719e2498dde70e4571c40474475a4af706a3cb82ac18a7fa44c22d1c4708839081808280098009098391089082827f8a0c3dc7a496adca059cb95d9b173812a00f3c4d435e0b9e8116e0c4b5f56acb08839081808280098009098391089082827f196bc98252f63169ed79073ee091a0e8ed0b5af51017da143940c00bdb86370908839081808280098009098391089082827fd979bf70695d93f8efb552a413701918afec9e12dfe213f4d0c27cfa68fad6c208839081808280098009098391089082827fb803072d02f54d237a3c6c4cc18eda6dce87a03c6819df54e4ed8aed6dc56d4608839081808280098009098391089082827f1efcda9d986cddcf431af4d59c6a7709d650885b7886cba70f0e7cd92b331cdc08839081808280098009098391089082827fd3ca5f7859b82ac50b63da06d43aa68a6b685f0a60397638bbea173b3f60419208839081808280098009098391089082827fa59d392c0667316ad37a06be2d51aabe9e79bdef0013bc109985648a14c7e41f08839081808280098009098391089082827fac2f5f0d2146791b396e2bed6cf15a20bc22cc4c8cf7dd4b3514ac00148dd0a708839081808280098009098391089082827f17a993a6af068d72bc36f0e814d29fef3f97d7a72aa963889b16a8457409861a08839081808280098009098391089082827f6f1bf99686550e0396f7f4e2df6fdaa090fbc272c8c76eb32a3c6791de5a07b508839081808280098009098391089082827f8234d705e1ecdc59cc6ed40749069d4b45e63deb49b5b7d7f527abd31c072b1b08839081808280098009098391089082827f6fe929a1fd6aacba5c4012c45dd727d2c816119567450003913d882cb97bc47e08839081808280098009098391089082827fad5371215f2aba49026b2e48739c11b4d8ffbb24dd4a6e41b9763862af96787a08839081808280098009098391089082827fd0e704566c49e1a11edc2c128b2e07f36dc0c755468268f8fe4c4859b9fa595b08839081808280098009098391089082827f263e1195090d00be1d8fb37de17ccf3b66d180645efa0d831865cfaa8797769e08839081808280098009098391089082827fe65c090eebde2cfa7f9c92cf75641c7683fb8e81f4a48f5b7a9c7eb26a85029f08839081808280098009098391089082827fa18971781c6855f6a9752912780bb9b719c14a677a4c6393d62d6e046b97a2ac08839081808280098009098391089082827ff6fc1ef1bca8bec055cc66edecc5dc99030fe78311a3f21d8cd624df4f89e62508839081808280098009098391089082827f824e4e2838501516d3296542cb47a59a1ca4326e947c9c874d88dccc8e37b99a08839081808280098009098391089082827f3cd5a9e7353a50e454c9c1381b556b543897cc89153c3e3749f2021d8237226308839081808280098009098391089082827fb4bcedbd54d0c917a315cc7ca785e3c5995abbeeb3deb3ebaf02c7a9bf6cc83f08839081808280098009098391089082827f1f7476211105b3039cef009c51155ae93526c53a74973ecfce40754b3df1052108839081808280098009098391089082827f58aefbd978440c94b4b9fbd36e00e6e36caeacf82b0da0a6161d34c541a5a6e308839081808280098009098391089082827fc22cd6d61be780a33c77677bc6ba40307b597ed981db57cb485313eec2a5a49708839081808280098009098391089082827fd9ffc4fe0dc5f835c8dcdc1e60b8f0b1637f32a809175371b94a057272b0748d08839081808280098009098391089082827ff6a5268541bc4c64ad0ade8f55dda3492604857a71c923662a214dd7e9c20c1008839081808280098009098391089082826000088390818082800980090983910860205260005260406000f3 diff --git a/tmp b/tmp new file mode 100644 index 0000000..4dc66d5 --- /dev/null +++ b/tmp @@ -0,0 +1,3 @@ +ADD -1 [stack(-1)] [stack(-1) = stack(-1) + (stack(-2)] +ADD -2 [stack(-2)] [stack(-2) = stack(-1) + (stack(-1)] +