From 9d89c280eb8e382ba406aa980ac5aae5ef92d7cf Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Fri, 20 Oct 2023 00:06:55 +0200 Subject: [PATCH 01/12] Lexer, Parser and AST --- Cargo.lock | 157 +++ Cargo.toml | 1 + frontend-wasm/src/code_translator/tests.rs | 72 +- frontend-wasm/tests/expected/signed_arith.mir | 140 ++- frontend-wasm/tests/expected/signed_arith.wat | 18 +- frontend-wasm/tests/test_rust_comp.rs | 95 +- hir-parser/Cargo.toml | 26 + hir-parser/README.md | 39 + hir-parser/build.rs | 5 + hir-parser/src/ast/block.rs | 92 ++ hir-parser/src/ast/functions.rs | 217 ++++ hir-parser/src/ast/globals.rs | 89 ++ hir-parser/src/ast/instruction.rs | 609 +++++++++++ hir-parser/src/ast/mod.rs | 146 +++ hir-parser/src/ast/types.rs | 90 ++ hir-parser/src/lexer/mod.rs | 970 ++++++++++++++++++ hir-parser/src/lib.rs | 107 ++ hir-parser/src/parser/grammar.lalrpop | 757 ++++++++++++++ hir-parser/src/parser/mod.rs | 257 +++++ hir-parser/src/symbols.rs | 163 +++ hir-transform/src/inline_blocks.rs | 51 +- hir-transform/src/split_critical_edges.rs | 26 +- hir-transform/src/treeify.rs | 20 +- hir/src/write.rs | 21 +- 24 files changed, 4079 insertions(+), 89 deletions(-) create mode 100644 hir-parser/Cargo.toml create mode 100644 hir-parser/README.md create mode 100644 hir-parser/build.rs create mode 100644 hir-parser/src/ast/block.rs create mode 100644 hir-parser/src/ast/functions.rs create mode 100644 hir-parser/src/ast/globals.rs create mode 100644 hir-parser/src/ast/instruction.rs create mode 100644 hir-parser/src/ast/mod.rs create mode 100644 hir-parser/src/ast/types.rs create mode 100644 hir-parser/src/lexer/mod.rs create mode 100644 hir-parser/src/lib.rs create mode 100644 hir-parser/src/parser/grammar.lalrpop create mode 100644 hir-parser/src/parser/mod.rs create mode 100644 hir-parser/src/symbols.rs diff --git a/Cargo.lock b/Cargo.lock index c5c79e499..e6ceb25cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,6 +112,15 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + [[package]] name = "atty" version = "0.2.14" @@ -144,6 +153,21 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -310,6 +334,12 @@ version = "0.100.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f333fa641a9ad2bff0b107767dcb972c18c2bfab7969805a1d7e42449ccb0408" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -391,6 +421,15 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + [[package]] name = "env_logger" version = "0.9.3" @@ -601,6 +640,17 @@ dependencies = [ "memoffset", ] +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi 0.3.2", + "rustix", + "windows-sys", +] + [[package]] name = "itertools" version = "0.10.5" @@ -637,6 +687,34 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "lalrpop" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" +dependencies = [ + "ascii-canvas", + "bit-set", + "diff", + "ena", + "is-terminal", + "itertools 0.10.5", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" + [[package]] name = "lazy_static" version = "1.4.0" @@ -883,6 +961,30 @@ dependencies = [ "smallvec", ] +[[package]] +name = "miden-ir-parser" +version = "0.4.0" +dependencies = [ + "lalrpop", + "lalrpop-util", + "lazy_static", + "miden-diagnostics", + "miden-parsing", + "pretty_assertions", + "regex", + "thiserror", +] + +[[package]] +name = "miden-parsing" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d36dfec2c0319b3773a83627318f92a0212077bed80148c86e8b09af60cd1a88" +dependencies = [ + "miden-diagnostics", + "thiserror", +] + [[package]] name = "midenc" version = "0.1.0" @@ -906,6 +1008,12 @@ dependencies = [ "adler", ] +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + [[package]] name = "num_cpus" version = "1.16.0" @@ -1002,6 +1110,21 @@ dependencies = [ "indexmap 2.0.0", ] +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -1226,12 +1349,31 @@ dependencies = [ "keccak", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "smallvec" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + [[package]] name = "strsim" version = "0.8.0" @@ -1328,6 +1470,15 @@ dependencies = [ "syn 2.0.31", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "toml" version = "0.7.6" @@ -1386,6 +1537,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index b0811b035..e286c4997 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" members = [ "codegen/*", "hir", + "hir-parser", "hir-analysis", "hir-pass", "hir-symbol", diff --git a/frontend-wasm/src/code_translator/tests.rs b/frontend-wasm/src/code_translator/tests.rs index 08be2e35c..60c2f0779 100644 --- a/frontend-wasm/src/code_translator/tests.rs +++ b/frontend-wasm/src/code_translator/tests.rs @@ -62,11 +62,15 @@ fn module() { pub fn main() { block0: + { v0 = const.i32 0 : i32 br block1 + } block1: - ret + { + ret + } } "#]], ); @@ -90,12 +94,16 @@ fn locals() { pub fn main() { block0: + { v0 = const.i32 0 : i32 v1 = const.i32 1 : i32 br block1 + } block1: - ret + { + ret + } } "#]], ); @@ -128,23 +136,31 @@ fn locals_inter_block() { pub fn main() -> i32 { block0: + { v1 = const.i32 0 : i32 v2 = const.i32 3 : i32 br block2 + } block1(v0: i32): - ret v0 + { + ret (v0) + } block2: + { v3 = const.i32 5 : i32 v4 = add v2, v3 : i32 br block3 + } block3: + { v5 = const.i32 7 : i32 v6 = add v5, v4 : i32 br block1(v6) } + } "#]], ); } @@ -171,22 +187,30 @@ fn func_call() { pub fn add(i32, i32) -> i32 { block0(v0: i32, v1: i32): + { v3 = add v0, v1 : i32 br block1(v3) + } block1(v2: i32): - ret v2 + { + ret (v2) + } } pub fn main() -> i32 { block0: + { v1 = const.i32 3 : i32 v2 = const.i32 5 : i32 v3 = call noname::add(v1, v2) : i32 br block1(v3) + } block1(v0: i32): - ret v0 + { + ret (v0) + } } "#]], ); @@ -212,16 +236,22 @@ fn br() { pub fn main() -> i32 { block0: + { v1 = const.i32 0 : i32 v2 = const.i32 3 : i32 br block2 + } block1(v0: i32): - ret v0 + { + ret (v0) + } block2: + { br block1(v2) } + } "#]], ); } @@ -255,26 +285,36 @@ fn loop_br_if() { pub fn main() -> i32 { block0: + { v1 = const.i32 0 : i32 v2 = const.i32 2 : i32 br block2(v2, v1) + } block1(v0: i32): - ret v0 + { + ret (v0) + } block2(v3: i32, v4: i32): + { v5 = add v3, v4 : i32 v6 = const.i32 1 : i32 v7 = sub v3, v6 : i32 v8 = neq v7, 0 : i1 condbr v8, block2(v7, v5), block4 + } block3: + { br block1(v5) + } block4: + { br block3 } + } "#]], ); } @@ -299,24 +339,34 @@ fn if_then_else() { pub fn main() -> i32 { block0: + { v1 = const.i32 2 : i32 v2 = neq v1, 0 : i1 condbr v2, block2, block4 + } block1(v0: i32): - ret v0 + { + ret (v0) + } block2: + { v4 = const.i32 3 : i32 br block3(v4) + } block3(v3: i32): + { br block1(v3) + } block4: + { v5 = const.i32 5 : i32 br block3(v5) } + } "#]], ); } @@ -342,15 +392,19 @@ fn global_var() { pub fn main() { block0: + { v0 = global.load (@MyGlobalVal) as *mut i8 : i32 v1 = const.i32 9 : i32 v2 = add v0, v1 : i32 v3 = global.symbol @MyGlobalVal : *mut i32 store v3, v2 br block1 + } block1: - ret + { + ret + } } "#]], ); diff --git a/frontend-wasm/tests/expected/signed_arith.mir b/frontend-wasm/tests/expected/signed_arith.mir index d4566efdb..7f16896c2 100644 --- a/frontend-wasm/tests/expected/signed_arith.mir +++ b/frontend-wasm/tests/expected/signed_arith.mir @@ -11,173 +11,234 @@ global external gv2 : i32 = 0x00100150 { id = gvar2 }; pub fn rust_begin_unwind(i32) { block0(v0: i32): +{ br block2 +} block1: +{ +} block2: +{ br block2 +} block3: +{ +} } pub fn div_s(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = eq v1, 0 : i1 v4 = cast v3 : i32 v5 = neq v4, 0 : i1 condbr v5, block3, block4 +} block1(v2: i32): - ret v2 +{ + ret (v2) +} block2: +{ v22 = div v0, v1 : i32 br block1(v22) +} block3: +{ v17 = const.i32 1048672 : i32 v18 = const.i32 25 : i32 v19 = const.i32 1048648 : i32 call noname::core::panicking::panic(v17, v18, v19) unreachable +} block4: +{ v6 = const.i32 -2147483648 : i32 v7 = neq v0, v6 : i1 v8 = cast v7 : i32 v9 = neq v8, 0 : i1 condbr v9, block2, block5 +} block5: +{ v10 = const.i32 -1 : i32 v11 = neq v1, v10 : i1 v12 = cast v11 : i32 v13 = neq v12, 0 : i1 condbr v13, block2, block6 +} block6: +{ v14 = const.i32 1048704 : i32 v15 = const.i32 31 : i32 v16 = const.i32 1048648 : i32 call noname::core::panicking::panic(v14, v15, v16) unreachable } +} pub fn div_u(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = eq v1, 0 : i1 v4 = cast v3 : i32 v5 = neq v4, 0 : i1 condbr v5, block2, block3 +} block1(v2: i32): +{ +} block2: +{ v10 = const.i32 1048672 : i32 v11 = const.i32 25 : i32 v12 = const.i32 1048736 : i32 call noname::core::panicking::panic(v10, v11, v12) unreachable +} block3: +{ v6 = cast v0 : u32 v7 = cast v1 : u32 v8 = div v6, v7 : u32 v9 = cast v8 : i32 - ret v9 + ret (v9) +} } pub fn rem_s(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = eq v1, 0 : i1 v4 = cast v3 : i32 v5 = neq v4, 0 : i1 condbr v5, block3, block4 +} block1(v2: i32): - ret v2 +{ + ret (v2) +} block2: +{ v22 = mod v0, v1 : i32 br block1(v22) +} block3: +{ v17 = const.i32 1048768 : i32 v18 = const.i32 57 : i32 v19 = const.i32 1048752 : i32 call noname::core::panicking::panic(v17, v18, v19) unreachable +} block4: +{ v6 = const.i32 -2147483648 : i32 v7 = neq v0, v6 : i1 v8 = cast v7 : i32 v9 = neq v8, 0 : i1 condbr v9, block2, block5 +} block5: +{ v10 = const.i32 -1 : i32 v11 = neq v1, v10 : i1 v12 = cast v11 : i32 v13 = neq v12, 0 : i1 condbr v13, block2, block6 +} block6: +{ v14 = const.i32 1048832 : i32 v15 = const.i32 48 : i32 v16 = const.i32 1048752 : i32 call noname::core::panicking::panic(v14, v15, v16) unreachable } +} pub fn rem_u(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = eq v1, 0 : i1 v4 = cast v3 : i32 v5 = neq v4, 0 : i1 condbr v5, block2, block3 +} block1(v2: i32): +{ +} block2: +{ v10 = const.i32 1048768 : i32 v11 = const.i32 57 : i32 v12 = const.i32 1048880 : i32 call noname::core::panicking::panic(v10, v11, v12) unreachable +} block3: +{ v6 = cast v0 : u32 v7 = cast v1 : u32 v8 = mod v6, v7 : u32 v9 = cast v8 : i32 - ret v9 + ret (v9) +} } pub fn shr_s(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = shr v0, v1 : i32 br block1(v3) +} block1(v2: i32): - ret v2 +{ + ret (v2) +} } pub fn shr_u(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = cast v0 : u32 v4 = cast v1 : u32 v5 = shr v3, v4 : u32 v6 = cast v5 : i32 br block1(v6) +} block1(v2: i32): - ret v2 +{ + ret (v2) +} } pub fn __main() -> i32 { block0: +{ v1 = const.i32 -8 : i32 v2 = const.i32 -4 : i32 v3 = call noname::div_s(v1, v2) : i32 @@ -202,61 +263,68 @@ block0: v22 = call noname::shr_u(v20, v21) : i32 v23 = add v19, v22 : i32 br block1(v23) +} block1(v0: i32): - ret v0 +{ + ret (v0) +} } pub fn core::ptr::drop_in_place(i32) { block0(v0: i32): +{ br block1 +} block1: - ret +{ + ret +} } pub fn core::panicking::panic_fmt(i32, i32) { block0(v0: i32, v1: i32): +{ v2 = const.i32 0 : i32 v3 = global.load (@__stack_pointer) as *mut i8 : i32 v4 = const.i32 32 : i32 v5 = sub v3, v4 : i32 v6 = global.symbol @__stack_pointer : *mut i32 store v6, v5 - v7 = cast v5 : u32 - v8 = add v7, 24 : u32 - v9 = inttoptr v8 : *mut i32 - store v9, v0 - v10 = const.i32 1048896 : i32 - v11 = cast v5 : u32 - v12 = add v11, 16 : u32 - v13 = inttoptr v12 : *mut i32 - store v13, v10 - v14 = const.i32 1048896 : i32 + v7 = const.i32 1 : i32 + v8 = trunc v7 : u16 + v9 = cast v5 : u32 + v10 = add v9, 28 : u32 + v11 = inttoptr v10 : *mut u16 + store v11, v8 + v12 = cast v5 : u32 + v13 = add v12, 24 : u32 + v14 = inttoptr v13 : *mut i32 + store v14, v1 v15 = cast v5 : u32 - v16 = add v15, 12 : u32 + v16 = add v15, 20 : u32 v17 = inttoptr v16 : *mut i32 - store v17, v14 - v18 = const.i32 1 : i32 - v19 = trunc v18 : u8 - v20 = cast v5 : u32 - v21 = add v20, 28 : u32 - v22 = inttoptr v21 : *mut u8 - store v22, v19 + store v17, v0 + v18 = const.i32 1048896 : i32 + v19 = cast v5 : u32 + v20 = add v19, 16 : u32 + v21 = inttoptr v20 : *mut i32 + store v21, v18 + v22 = const.i32 1048896 : i32 v23 = cast v5 : u32 - v24 = add v23, 20 : u32 + v24 = add v23, 12 : u32 v25 = inttoptr v24 : *mut i32 - store v25, v1 + store v25, v22 v26 = const.i32 12 : i32 v27 = add v5, v26 : i32 call noname::rust_begin_unwind(v27) unreachable - -block1: } pub fn core::panicking::panic(i32, i32, i32) { block0(v0: i32, v1: i32, v2: i32): +{ v3 = const.i32 0 : i32 v4 = global.load (@__stack_pointer) as *mut i8 : i32 v5 = const.i32 32 : i32 @@ -294,23 +362,25 @@ block0(v0: i32, v1: i32, v2: i32): store v30, v28 call noname::core::panicking::panic_fmt(v6, v2) unreachable - -block1: } pub fn ::type_id(i32, i32) { block0(v0: i32, v1: i32): - v2 = const.i64 -1688046730280208939 : i64 +{ + v2 = const.i64 -8014429818408747214 : i64 v3 = cast v0 : u32 v4 = add v3, 8 : u32 v5 = inttoptr v4 : *mut i64 store v5, v2 - v6 = const.i64 -2518113060735759681 : i64 + v6 = const.i64 167320651382453006 : i64 v7 = cast v0 : u32 v8 = inttoptr v7 : *mut i64 store v8, v6 br block1 +} block1: - ret +{ + ret +} } diff --git a/frontend-wasm/tests/expected/signed_arith.wat b/frontend-wasm/tests/expected/signed_arith.wat index 03655d922..5f9222b05 100644 --- a/frontend-wasm/tests/expected/signed_arith.wat +++ b/frontend-wasm/tests/expected/signed_arith.wat @@ -145,21 +145,21 @@ local.tee 2 global.set $__stack_pointer local.get 2 - local.get 0 + i32.const 1 + i32.store16 offset=28 + local.get 2 + local.get 1 i32.store offset=24 local.get 2 + local.get 0 + i32.store offset=20 + local.get 2 i32.const 1048896 i32.store offset=16 local.get 2 i32.const 1048896 i32.store offset=12 local.get 2 - i32.const 1 - i32.store8 offset=28 - local.get 2 - local.get 1 - i32.store offset=20 - local.get 2 i32.const 12 i32.add call $rust_begin_unwind @@ -201,10 +201,10 @@ ) (func $::type_id (;11;) (type 3) (param i32 i32) local.get 0 - i64.const -1688046730280208939 + i64.const -8014429818408747214 i64.store offset=8 local.get 0 - i64.const -2518113060735759681 + i64.const 167320651382453006 i64.store ) (table (;0;) 3 3 funcref) diff --git a/frontend-wasm/tests/test_rust_comp.rs b/frontend-wasm/tests/test_rust_comp.rs index e03510e6b..82b2b1a89 100644 --- a/frontend-wasm/tests/test_rust_comp.rs +++ b/frontend-wasm/tests/test_rust_comp.rs @@ -213,22 +213,30 @@ fn rust_add() { pub fn add(i32, i32) -> i32 { block0(v0: i32, v1: i32): + { v3 = add v1, v0 : i32 br block1(v3) + } block1(v2: i32): - ret v2 + { + ret (v2) + } } pub fn __main() -> i32 { block0: + { v1 = const.i32 1 : i32 v2 = const.i32 2 : i32 v3 = call noname::add(v1, v2) : i32 br block1(v3) + } block1(v0: i32): - ret v0 + { + ret (v0) + } } "#]], ); @@ -293,37 +301,53 @@ fn rust_fib() { pub fn fib(i32) -> i32 { block0(v0: i32): + { v2 = const.i32 0 : i32 v3 = const.i32 0 : i32 v4 = const.i32 1 : i32 br block2(v4, v0, v3) + } block1(v1: i32): + { + } block2(v6: i32, v7: i32, v9: i32): + { v8 = neq v7, 0 : i1 condbr v8, block4, block5 + } block3(v5: i32): + { + } block4: + { v10 = const.i32 -1 : i32 v11 = add v7, v10 : i32 v12 = add v9, v6 : i32 br block2(v12, v11, v6) + } block5: - ret v9 + { + ret (v9) + } } pub fn __main() -> i32 { block0: + { v1 = const.i32 25 : i32 v2 = call noname::fib(v1) : i32 br block1(v2) + } block1(v0: i32): - ret v0 + { + ret (v0) + } } "#]], ); @@ -395,29 +419,40 @@ fn rust_enum() { pub fn match_enum(i32, i32, i32) -> i32 { block0(v0: i32, v1: i32, v2: i32): + { v4 = const.i32 255 : i32 v5 = band v2, v4 : i32 v6 = cast v5 : u32 switch v6, 0 => block4, 1 => block3, 2 => block2, block4 + } block1(v3: i32): - ret v3 + { + ret (v3) + } block2: + { v9 = mul v1, v0 : i32 br block1(v9) + } block3: + { v8 = sub v0, v1 : i32 - ret v8 + ret (v8) + } block4: + { v7 = add v1, v0 : i32 - ret v7 + ret (v7) + } } pub fn __main() -> i32 { block0: + { v1 = const.i32 3 : i32 v2 = const.i32 5 : i32 v3 = const.i32 0 : i32 @@ -433,9 +468,12 @@ fn rust_enum() { v13 = call noname::match_enum(v10, v11, v12) : i32 v14 = add v9, v13 : i32 br block1(v14) + } block1(v0: i32): - ret v0 + { + ret (v0) + } } "#]], ) @@ -510,23 +548,32 @@ fn rust_array() { pub fn sum_arr(i32, i32) -> i32 { block0(v0: i32, v1: i32): + { v3 = const.i32 0 : i32 v4 = const.i32 0 : i32 v5 = eq v1, 0 : i1 v6 = cast v5 : i32 v7 = neq v6, 0 : i1 condbr v7, block2(v4), block3 + } block1(v2: i32): - ret v2 + { + ret (v2) + } block2(v20: i32): + { br block1(v20) + } block3: + { br block4(v0, v4, v1) + } block4(v8: i32, v12: i32, v16: i32): + { v9 = cast v8 : u32 v10 = inttoptr v9 : *mut i32 v11 = load v10 : i32 @@ -537,16 +584,22 @@ fn rust_array() { v18 = add v16, v17 : i32 v19 = neq v18, 0 : i1 condbr v19, block4(v15, v13, v18), block6 + } block5: + { br block2(v13) + } block6: + { br block5 } + } pub fn __main() -> i32 { block0: + { v1 = const.i32 1048576 : i32 v2 = const.i32 5 : i32 v3 = call noname::sum_arr(v1, v2) : i32 @@ -555,9 +608,12 @@ fn rust_array() { v6 = call noname::sum_arr(v4, v5) : i32 v7 = add v3, v6 : i32 br block1(v7) + } block1(v0: i32): - ret v0 + { + ret (v0) + } } "#]], ) @@ -631,6 +687,7 @@ fn rust_static_mut() { pub fn global_var_update() { block0: + { v0 = const.i32 0 : i32 v1 = const.i32 0 : i32 v2 = cast v1 : u32 @@ -646,23 +703,31 @@ fn rust_static_mut() { v12 = inttoptr v11 : *mut u8 store v12, v9 br block1 + } block1: - ret + { + ret + } } pub fn __main() -> i32 { block0: + { v1 = const.i32 0 : i32 call noname::global_var_update() v2 = const.i32 0 : i32 v3 = const.i32 -9 : i32 br block2(v3, v2) + } block1(v0: i32): - ret v0 + { + ret (v0) + } block2(v4: i32, v11: i32): + { v5 = const.i32 1048585 : i32 v6 = add v4, v5 : i32 v7 = cast v6 : u32 @@ -674,15 +739,20 @@ fn rust_static_mut() { v14 = add v4, v13 : i32 v15 = neq v14, 0 : i1 condbr v15, block2(v14, v12), block4 + } block3: + { v16 = const.i32 255 : i32 v17 = band v12, v16 : i32 br block1(v17) + } block4: + { br block3 } + } "#]], ); } @@ -697,6 +767,7 @@ fn dlmalloc() { } #[test] +#[ignore = "Being reworked"] fn signed_arith() { check_ir_files( include_str!("rust_source/signed_arith.rs"), diff --git a/hir-parser/Cargo.toml b/hir-parser/Cargo.toml new file mode 100644 index 000000000..65e5e6e06 --- /dev/null +++ b/hir-parser/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "miden-ir-parser" +version = "0.4.0" +description = "Parser for the Miden IR language" +authors = ["miden contributors"] +readme = "README.md" +license = "MIT" +repository = "https://github.com/0xPolygonMiden/miden-ir" +categories = ["Compilers"] +keywords = ["compiler", "miden"] +edition = "2021" +rust-version = "1.67" + +[build-dependencies] +lalrpop = { version = "0.20", default-features = false } + +[dependencies] +miden-diagnostics = "0.1" +miden-parsing = "0.1" +lalrpop-util="0.20" +lazy_static = "1.4" +regex = "1" +thiserror = "1.0" + +[dev-dependencies] +pretty_assertions = "1.0" diff --git a/hir-parser/README.md b/hir-parser/README.md new file mode 100644 index 000000000..a6d7558cc --- /dev/null +++ b/hir-parser/README.md @@ -0,0 +1,39 @@ +# Parser + +This crate contains the parser for Miden IR. + +The purpose of the parser is to parse the Miden IR language into an Abstract Syntax Tree. + +## Generating the Abstract Syntax Tree (AST) + +The parser uses [Logos](https://github.com/maciejhirsz/logos/) to generate a custom lexer, which is then fed into the parser generated by [LALRPOP](https://github.com/lalrpop/lalrpop/). + +To create an AST from a given Miden IR program or module, pass your source to the public `parse` function, which will return the AST or an `Error` of type `ScanError` or `ParseError`. + +The `parse` function will first tokenize the source using the lexer, then map the resulting tokens to new tokens accepted by the parser, which are of type `(usize, Token, usize)`. Each invalid token will be stored as `ScanError`. Finally, if no `ScanError` occurred, `parse` feeds the tokens to the parser to generate a Result with the corresponding AST (or `ParseError`). + +Example usage: + +```Rust +// parse the source string to a Result containing the AST or an Error +let ast = parse(source.as_str()); +``` + +## AST + +The Miden IR AST (`Source`) contains a vector of `SourceSection`, each of which contains the result of parsing a section in a Miden IR program or module. + + + +TODO: + +The `SourceSection` types are: + +- `AirDef`, which holds the name of the AIR. +- `Constant`, which holds a named constant to be used to write constraints. +- `Trace`, which contains the parsed trace column information for the main and auxiliary execution traces. Each column or group of columns is represented by its identifier and can be accessed in constraints using this identifier. These columns can also be accessed using the built-in variables `$main[idx]` and `$aux[idx]`, where `idx` is the index of the column in the trace. +- `PublicInputs`, which is a vector of all of the public inputs defined in the module. Each public input is represented by its identifier and a fixed size. +- `PeriodicColumns`, which is a vector of all of the periodic columns defined in the module. Each periodic column is represented by its identifier and a vector containing the pattern of its repeated (periodic) values. +- `RandomValues`, which is a vector of all of the random values provided by the verifier. Each random value or group of random values is represented by its identifier and can be accessed in constraints using this identifier. These random values can also be accessed using `$rand[idx]`, where `rand` is the name of the random values array and `idx` is the index of the random value in that array. +- `BoundaryConstraints`, which contains a vector of `BoundaryStmt` statements, each of which can be either a boundary constraint or an intermediate variable. Each boundary constraint is represented as an expression tree. Variables can be scalars, vectors or matrices containing expression trees. +- `IntegrityConstraints`, which contains a vector of `IntegrityStmt` statements, each of which can be either an integrity constraint or an intermediate variable. Each integrity constraint is represented as an expression tree. Variables can be scalars, vectors or matrices containing expression trees. \ No newline at end of file diff --git a/hir-parser/build.rs b/hir-parser/build.rs new file mode 100644 index 000000000..23c7d3f80 --- /dev/null +++ b/hir-parser/build.rs @@ -0,0 +1,5 @@ +extern crate lalrpop; + +fn main() { + lalrpop::process_root().unwrap(); +} diff --git a/hir-parser/src/ast/block.rs b/hir-parser/src/ast/block.rs new file mode 100644 index 000000000..a7da7d592 --- /dev/null +++ b/hir-parser/src/ast/block.rs @@ -0,0 +1,92 @@ +use super::*; + +const INDENT: &str = " "; + +/// Represents the label at the start of a basic block. +/// +/// Labels must be unique within each function. +pub struct Label { + pub name: Identifier, +} +impl Label { + pub fn new(name: Identifier) -> Self { + Self { name } + } +} +impl fmt::Display for Label { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name) + } +} + +/// Represents an argument for a basic block +pub struct BlockArgument { + pub value: Value, + pub ty: Type, +} +impl BlockArgument { + pub fn new(value: Value, ty: Type) -> Self { + Self { value, ty } + } +} +impl fmt::Display for BlockArgument { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} : {} ", self.value, self.ty) + } +} + +/// Represents the label and the arguments of a basic block +pub struct BlockHeader { + pub label: Label, + pub args: Vec, +} +impl BlockHeader { + pub fn new(label: Label, args: Vec) -> Self { + Self { label, args } + } +} +impl fmt::Display for BlockHeader { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} ", self.label)?; + if self.args.len() == 0 { + f.write_str(":\n") + } else { + f.write_str("(")?; + for (i, arg) in self.args.iter().enumerate() { + if i != 0 { + write!(f, ", {}", arg)?; + } else { + write!(f, "{}", arg)?; + } + } + f.write_str(") :\n") + } + } +} + +/// Represents a basic block of instructions +#[derive(Spanned)] +pub struct Block { + #[span] + pub span: SourceSpan, + pub header: BlockHeader, + pub instructions: Vec, +} +impl Block { + pub fn new(span: SourceSpan, header: BlockHeader, instructions: Vec) -> Self { + Self { + span, + header, + instructions, + } + } +} +impl fmt::Display for Block { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "{}", self.header)?; + for inst in self.instructions.iter() { + writeln!(f, "{}{}", INDENT, inst)?; + } + Ok(()) + } +} diff --git a/hir-parser/src/ast/functions.rs b/hir-parser/src/ast/functions.rs new file mode 100644 index 000000000..44df73b97 --- /dev/null +++ b/hir-parser/src/ast/functions.rs @@ -0,0 +1,217 @@ +use super::*; + +/// Represents an identifier that represents a function name. +/// +/// A function identifier is a non-empty sequence of identifiers, separated by double +/// colons ("::"). The last identifier in the sequence denotes the name of the function +/// itself. The other identifiers denote the module that the function can be found in. If +/// the function identifier only consists of a single identifier, then the function must +/// be found in the current module. +#[derive(Spanned)] +pub struct FunctionIdentifier { + #[span] + span: SourceSpan, + names: Vec, +} +impl FunctionIdentifier { + pub fn new(span: SourceSpan, names: Vec) -> Self { + Self { span, names } + } + + pub fn id(&self) -> &Identifier { + self.names.last().unwrap() + } +} +impl fmt::Display for FunctionIdentifier { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for (i, id) in self.names.iter().enumerate() { + if i > 0 { + f.write_str("::")?; + } + write!(f, "{}", id)?; + } + Ok(()) + } +} + +/// The possible visibilities of a function +pub enum Visibility { + /// (Module) private visibility + Private, + /// Public visibility + Public, +} + +/// The possible calling convetions of a function +pub enum CallConvention { + /// Default call convention + Default, + /// Kernel call convention + Kernel, + /// Fast call convention + Fast, +} + +/// The possible purposes of a function parameter +pub enum ParameterPurpose { + /// Standard parameter + Standard, + /// Parameter for struct return + Sret, +} + +/// The possible extensions of a function parameter when filling up a word +pub enum ParameterExtension { + /// No extension + None, + /// 0 extended + Zero, + /// Sign extended + Signed, +} + +/// A single parameter to a function. +/// Parameter names are defined in the entry block for the function. +pub struct FunctionParameter { + /// The purpose of the parameter (default or struct return) + pub purpose: ParameterPurpose, + /// The bit extension for the parameter + pub extension: ParameterExtension, + /// The type of the parameter + pub ty: Type, +} +impl FunctionParameter { + pub fn new(purpose: ParameterPurpose, extension: ParameterExtension, ty: Type) -> Self { + Self { + purpose, + extension, + ty, + } + } +} +impl fmt::Display for FunctionParameter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.purpose { + ParameterPurpose::Standard => Ok(()), + ParameterPurpose::Sret => f.write_str("sret "), + }?; + match self.extension { + ParameterExtension::None => Ok(()), + ParameterExtension::Zero => f.write_str("zext "), + ParameterExtension::Signed => f.write_str("sext "), + }?; + write!(f, "{}", self.ty) + } +} + +/// A single return value from a function. +pub struct FunctionReturn { + /// The bit extension for the parameter + pub extension: ParameterExtension, + /// The type of the parameter + pub ty: Type, +} +impl FunctionReturn { + pub fn new(extension: ParameterExtension, ty: Type) -> Self { + Self { extension, ty } + } +} +impl fmt::Display for FunctionReturn { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.extension { + ParameterExtension::None => Ok(()), + ParameterExtension::Zero => f.write_str("zext "), + ParameterExtension::Signed => f.write_str("sext "), + }?; + write!(f, "{}", self.ty) + } +} + +/// Represents the type signature of a function +#[derive(Spanned)] +pub struct FunctionSignature { + #[span] + pub span: SourceSpan, + pub visibility: Visibility, + pub call_convention: CallConvention, + pub name: FunctionIdentifier, + pub params: Vec, + pub returns: Vec, +} +impl FunctionSignature { + pub fn new( + span: SourceSpan, + visibility: Visibility, + call_convention: CallConvention, + name: FunctionIdentifier, + params: Vec, + returns: Vec, + ) -> Self { + Self { + span, + visibility, + call_convention, + name, + params, + returns, + } + } +} +impl fmt::Display for FunctionSignature { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.visibility { + Visibility::Private => Ok(()), + Visibility::Public => f.write_str("pub "), + }?; + match self.call_convention { + CallConvention::Default => Ok(()), + CallConvention::Kernel => f.write_str("kernel "), + CallConvention::Fast => f.write_str("fast "), + }?; + write!(f, "{}(", self.name)?; + for (i, param) in self.params.iter().enumerate() { + if i != 0 { + write!(f, ", {}", param)?; + } else { + write!(f, "{}", param)?; + } + } + f.write_str(")")?; + for (i, ret) in self.returns.iter().enumerate() { + if i != 0 { + write!(f, ", {}", ret)?; + } else { + write!(f, "{}", ret)?; + } + } + Ok(()) + } +} + +/// Represents the declaration of a function +#[derive(Spanned)] +pub struct FunctionDeclaration { + #[span] + pub span: SourceSpan, + pub signature: FunctionSignature, + pub blocks: Vec, +} +impl FunctionDeclaration { + pub fn new(span: SourceSpan, signature: FunctionSignature, blocks: Vec) -> Self { + Self { + span, + signature, + blocks, + } + } +} +impl fmt::Display for FunctionDeclaration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.signature)?; + f.write_str("{{\n")?; + for block in self.blocks.iter() { + write!(f, "{}", block)?; + } + f.write_str("}}\n") + } +} diff --git a/hir-parser/src/ast/globals.rs b/hir-parser/src/ast/globals.rs new file mode 100644 index 000000000..465b6f23a --- /dev/null +++ b/hir-parser/src/ast/globals.rs @@ -0,0 +1,89 @@ +use std::fmt; + +use miden_diagnostics::{SourceSpan, Spanned}; + +use super::*; + +/// This is a type alias used to clarify that an identifier refers to a global variable +pub type GlobalVarId = Identifier; + +/// A constant value in the form of a hexadecimal string +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GlobalVarInitializer { + pub data: Vec, +} +impl GlobalVarInitializer { + pub fn new(data: Vec) -> Self { + Self { data } + } +} +impl fmt::Display for GlobalVarInitializer { + /// Print the constant data in hexadecimal format, e.g. 0x000102030405060708090a0b0c0d0e0f. + /// + /// The printed form of the constant renders the bytes in big-endian order, for readability. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if !self.data.is_empty() { + write!(f, "0x")?; + for b in self.data.iter().rev() { + write!(f, "{:02x}", b)?; + } + } + Ok(()) + } +} + +/// This represents the declaration of a Miden IR global variable +#[derive(Spanned)] +pub struct GlobalVarDeclaration { + #[span] + pub span: SourceSpan, + pub name: GlobalVarId, + pub ty: Type, + pub linkage: Linkage, + pub init: Option, +} +impl GlobalVarDeclaration { + /// Constructs a new global variable, with the given span, name, type, linkage, and optinal initializer. + /// + pub fn new(span: SourceSpan, name: ModuleId, ty: Type, linkage: Linkage) -> Self { + Self { + span: span, + name: name, + ty: ty, + linkage: linkage, + init: None, + } + } + + pub fn with_init(&mut self, init: GlobalVarInitializer) { + self.init = Some(init) + } +} +impl fmt::Display for GlobalVarDeclaration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {} {}", self.name, self.ty, self.linkage)?; + if self.init.is_some() { + write!(f, "= {}", self.init.as_ref().unwrap())?; + } + Ok(()) + } +} +/// Represents the intended linkage for a global variable. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum Linkage { + /// Global linkage + Internal, + /// "One definition rule" linkage + Odr, + /// External linkage + External, +} +impl fmt::Display for Linkage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Internal => write!(f, "internal"), + Self::Odr => write!(f, "odr"), + Self::External => write!(f, "external"), + } + } +} diff --git a/hir-parser/src/ast/instruction.rs b/hir-parser/src/ast/instruction.rs new file mode 100644 index 000000000..72a837058 --- /dev/null +++ b/hir-parser/src/ast/instruction.rs @@ -0,0 +1,609 @@ +use super::*; + +/// Represents a value in Miden IR. +/// +/// All intermediate values are named, and have an associated [Value]. +/// Value identifiers must be globally unique. +pub struct Value { + pub name: Identifier, +} +impl Value { + pub fn new(name: Identifier) -> Self { + Self { name } + } +} +impl fmt::Display for Value { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.name) + } +} + +/// Immediates are converted at a later stage +pub enum Immediate { + Pos(u128), + Neg(u128), +} +impl fmt::Display for Immediate { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Pos(0) | Self::Neg(0) => f.write_str("0"), + Self::Pos(v) => write!(f, "{}", v), + Self::Neg(v) => write!(f, "-{}", v), + } + } +} + +/// Represents a single instruction. +/// +/// An instruction consists of a single operation, and a number of values that +/// represent the results of the operation. Additionally, the instruction contains +/// the types of the produced results +#[derive(Spanned)] +pub struct Instruction { + #[span] + pub span: SourceSpan, + pub values: Vec, + pub op: Operation, + pub types: Vec, +} +impl Instruction { + pub fn new(span: SourceSpan, values: Vec, op: Operation, types: Vec) -> Self { + Self { + span, + values, + op, + types, + } + } +} +impl fmt::Display for Instruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.values.len() == 0 { + write!(f, "{}", self.op)?; + } else { + for (i, v) in self.values.iter().enumerate() { + if i != 0 { + write!(f, ", {}", v)?; + } else { + write!(f, "{}", v)?; + } + } + write!(f, " = {} : ", self.op)?; + for (i, t) in self.types.iter().enumerate() { + if i != 0 { + write!(f, ", {}", t)?; + } else { + write!(f, "{}", t)?; + } + } + } + Ok(()) + } +} + +/// Represents a operation and its arguments +pub enum Operation { + BinaryOp(BinaryOpCode, Value, Value), + BinaryImmOp(BinaryImmOpCode, Value, Immediate), + UnaryOp(UnaryOpCode, Value), + UnaryImmOp(UnaryImmOpCode, Immediate), + ReturnOp(Vec), + CallOp(CallOp, FunctionIdentifier, Vec), + CondOp(Value, Destination, Destination), + BranchOp(Destination), + SwitchOp(Value, Vec), + TestOp(Type, Value), + PrimOp(PrimOpCode, Vec), + LoadOp(Value), + MemCpyOp(Type, Value, Value, Value), + GlobalValueOp(GlobalValueOp), +} +impl fmt::Display for Operation { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::BinaryOp(op, v1, v2) => { + write!(f, "{} {} {}", op, v1, v2) + } + Self::BinaryImmOp(op, v, i) => { + write!(f, "{} {} {}", op, v, i) + } + Self::UnaryOp(op, v) => { + write!(f, "{} {}", op, v) + } + Self::UnaryImmOp(op, i) => { + write!(f, "{} {}", op, i) + } + Self::ReturnOp(vs) => { + f.write_str("ret")?; + for (i, v) in vs.iter().enumerate() { + if i > 0 { + f.write_str(",")?; + } + write!(f, " {}", v)?; + } + Ok(()) + } + Self::CallOp(op, id, vs) => { + write!(f, "{} {} (", op, id)?; + for (i, v) in vs.iter().enumerate() { + if i > 0 { + f.write_str(", ")?; + } + write!(f, "{}", v)?; + } + f.write_str(")") + } + Self::CondOp(v, dest1, dest2) => { + write!(f, "cond {}, {}, {}", v, dest1, dest2) + } + Self::BranchOp(dest) => { + write!(f, "branch {}", dest) + } + Self::SwitchOp(v, branches) => { + writeln!(f, "switch {} {{", v)?; + for (i, b) in branches.iter().enumerate() { + if i > 0 { + f.write_str(",\n")?; + } + //TODO: Indentation + write!(f, "{}", b)?; + } + //TODO: Indentation + f.write_str("\n}}") + } + Self::TestOp(t, v) => { + write!(f, "test.{} {}", t, v) + } + Self::PrimOp(op, vs) => { + write!(f, "{}", op)?; + for (i, v) in vs.iter().enumerate() { + if i > 0 { + f.write_str(",")?; + } + write!(f, " {}", v)?; + } + Ok(()) + } + Self::LoadOp(v) => { + write!(f, "load {}", v) + } + Self::MemCpyOp(t, v1, v2, v3) => { + write!(f, "memcpy.{} {}, {}, {}", t, v1, v2, v3) + } + Self::GlobalValueOp(op) => { + write!(f, "{}", op) + } + } + } +} + +/// Used to distinguish between user calls and kernel calls +pub enum CallOp { + Call, + SysCall, +} +impl fmt::Display for CallOp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Call => f.write_str("call"), + Self::SysCall => f.write_str("syscall"), + } + } +} + +/// Used to distinguish between binary operations +pub enum BinaryOpCode { + Add(Overflow), + Sub(Overflow), + Mul(Overflow), + Div(Overflow), + Min(Overflow), + Max(Overflow), + Mod(Overflow), + DivMod(Overflow), + Exp(Overflow), + And, + BAnd(Overflow), + Or, + BOr(Overflow), + Xor, + BXor(Overflow), + Shl(Overflow), + Shr(Overflow), + Rotl(Overflow), + Rotr(Overflow), + Eq, + Neq, + Gt, + Gte, + Lt, + Lte, + Store, +} +impl fmt::Display for BinaryOpCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Add(overflow) => { + write!(f, "add.{}", overflow) + } + Self::Sub(overflow) => { + write!(f, "sub.{}", overflow) + } + Self::Mul(overflow) => { + write!(f, "mul.{}", overflow) + } + Self::Div(overflow) => { + write!(f, "div.{}", overflow) + } + Self::Min(overflow) => { + write!(f, "min.{}", overflow) + } + Self::Max(overflow) => { + write!(f, "max.{}", overflow) + } + Self::Mod(overflow) => { + write!(f, "mod.{}", overflow) + } + Self::DivMod(overflow) => { + write!(f, "divmod.{}", overflow) + } + Self::Exp(overflow) => { + write!(f, "exp.{}", overflow) + } + Self::And => f.write_str("and"), + Self::BAnd(overflow) => { + write!(f, "band.{}", overflow) + } + Self::Or => f.write_str("or"), + Self::BOr(overflow) => { + write!(f, "bor.{}", overflow) + } + Self::Xor => f.write_str("xor"), + Self::BXor(overflow) => { + write!(f, "bxor.{}", overflow) + } + Self::Shl(overflow) => { + write!(f, "shl.{}", overflow) + } + Self::Shr(overflow) => { + write!(f, "shr.{}", overflow) + } + Self::Rotl(overflow) => { + write!(f, "rotl.{}", overflow) + } + Self::Rotr(overflow) => { + write!(f, "rotr.{}", overflow) + } + Self::Eq => f.write_str("eq"), + Self::Neq => f.write_str("neq"), + Self::Gt => f.write_str("gt"), + Self::Gte => f.write_str("gte"), + Self::Lt => f.write_str("lt"), + Self::Lte => f.write_str("lte"), + Self::Store => f.write_str("store"), + } + } +} + +/// Used to distinguish between immediate binary operations +pub enum BinaryImmOpCode { + AddImm(Overflow), + SubImm(Overflow), + MulImm(Overflow), + DivImm(Overflow), + MinImm(Overflow), + MaxImm(Overflow), + ModImm(Overflow), + DivModImm(Overflow), + ExpImm(Overflow), + AndImm, + BAndImm(Overflow), + OrImm, + BOrImm(Overflow), + XorImm, + BXorImm(Overflow), + ShlImm(Overflow), + ShrImm(Overflow), + RotlImm(Overflow), + RotrImm(Overflow), +} +impl fmt::Display for BinaryImmOpCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::AddImm(overflow) => { + write!(f, "add_imm.{}", overflow) + } + Self::SubImm(overflow) => { + write!(f, "sub_imm.{}", overflow) + } + Self::MulImm(overflow) => { + write!(f, "mul_imm.{}", overflow) + } + Self::DivImm(overflow) => { + write!(f, "div_imm.{}", overflow) + } + Self::MinImm(overflow) => { + write!(f, "min_imm.{}", overflow) + } + Self::MaxImm(overflow) => { + write!(f, "max_imm.{}", overflow) + } + Self::ModImm(overflow) => { + write!(f, "mod_imm.{}", overflow) + } + Self::DivModImm(overflow) => { + write!(f, "divmod_imm.{}", overflow) + } + Self::ExpImm(overflow) => { + write!(f, "exp_imm.{}", overflow) + } + Self::AndImm => f.write_str("and"), + Self::BAndImm(overflow) => { + write!(f, "band_imm.{}", overflow) + } + Self::OrImm => f.write_str("or"), + Self::BOrImm(overflow) => { + write!(f, "bor_imm.{}", overflow) + } + Self::XorImm => f.write_str("xor"), + Self::BXorImm(overflow) => { + write!(f, "bxor_imm.{}", overflow) + } + Self::ShlImm(overflow) => { + write!(f, "shl_imm.{}", overflow) + } + Self::ShrImm(overflow) => { + write!(f, "shr_imm.{}", overflow) + } + Self::RotlImm(overflow) => { + write!(f, "rotl_imm.{}", overflow) + } + Self::RotrImm(overflow) => { + write!(f, "rotr_imm.{}", overflow) + } + } + } +} + +/// Used to distinguish between unary operations +pub enum UnaryOpCode { + Inv, + Incr, + Pow2, + Not, + BNot, + PopCnt, + IsOdd, + Cast, + PtrToInt, + IntToPtr, + TruncW, + Zext, + Sext, + Neg, +} +impl fmt::Display for UnaryOpCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Inv => f.write_str("inv"), + Self::Incr => f.write_str("incr"), + Self::Pow2 => f.write_str("pow2"), + Self::Not => f.write_str("not"), + Self::BNot => f.write_str("bnot"), + Self::PopCnt => f.write_str("popcnt"), + Self::IsOdd => f.write_str("is_odd"), + Self::Cast => f.write_str("cast"), + Self::PtrToInt => f.write_str("ptrtoint"), + Self::IntToPtr => f.write_str("inttoptr"), + Self::TruncW => f.write_str("truncw"), + Self::Zext => f.write_str("zext"), + Self::Sext => f.write_str("sext"), + Self::Neg => f.write_str("neg"), + } + } +} + +/// Used to distinguish between immediate unary operations +pub enum UnaryImmOpCode { + I1, + I8, + I16, + I32, + I64, + ISize, + Felt, + F64, +} +impl fmt::Display for UnaryImmOpCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("const.")?; + match self { + Self::I1 => f.write_str("i1"), + Self::I8 => f.write_str("i8"), + Self::I16 => f.write_str("i16"), + Self::I32 => f.write_str("i32"), + Self::I64 => f.write_str("i64"), + Self::ISize => f.write_str("isize"), + Self::Felt => f.write_str("felt"), + Self::F64 => f.write_str("f64"), + } + } +} + +/// Used to distinguish between primary operations +pub enum PrimOpCode { + Select, + Assert, + Assertz, + AssertEq, + Alloca, + Unreachable, +} +impl fmt::Display for PrimOpCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Select => f.write_str("select"), + Self::Assert => f.write_str("assert"), + Self::Assertz => f.write_str("assertz"), + Self::AssertEq => f.write_str("asserteq"), + Self::Alloca => f.write_str("alloca"), + Self::Unreachable => f.write_str("unreachable"), + } + } +} + +/// Memory offset for global variable reads. +/// Conversion to i32 happens during transformation to hir. +pub enum Offset { + Pos(u128), + Neg(u128), +} +impl Offset { + pub fn is_zero(&self) -> bool { + match self { + Self::Pos(offset) | Self::Neg(offset) => offset == &0, + } + } +} +impl fmt::Display for Offset { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Pos(offset) => { + if offset > &0 { + write!(f, "+{}", offset)?; + } + } + Self::Neg(offset) => { + if offset > &0 { + write!(f, "-{}", offset)?; + } + } + } + Ok(()) + } +} + +/// Used to distinguish between nested global value operations +pub enum GlobalValueOpNested { + Symbol(Identifier, Offset), + Load(Box, Offset), + Cast(Box, Offset, Type), +} +impl fmt::Display for GlobalValueOpNested { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Symbol(id, offset) => { + write!(f, "@ {} {}", id, offset) + } + Self::Load(nested, offset) => { + f.write_str("* ")?; + if offset.is_zero() { + write!(f, "{}", nested)?; + } else { + write!(f, "({}){}", nested, offset)?; + } + Ok(()) + } + Self::Cast(nested, offset, ty) => { + write!(f, "* ({}) {} as {}", nested, offset, ty) + } + } + } +} + +/// Used to distinguish between top-level global value operations +pub enum GlobalValueOp { + Symbol(Identifier, Offset), + Load(GlobalValueOpNested, Offset), + Cast(GlobalValueOpNested, Offset, Type), + IAddImm(u128, Type, GlobalValueOpNested), +} +impl fmt::Display for GlobalValueOp { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("global.")?; + match self { + Self::Symbol(id, offset) => { + write!(f, "symbol @ {} {}", id, offset) + } + Self::Load(nested, offset) => { + f.write_str("load ")?; + if offset.is_zero() { + write!(f, "{}", nested)?; + } else { + write!(f, "({}) {}", nested, offset)?; + } + Ok(()) + } + Self::Cast(nested, offset, ty) => { + write!(f, "load ({}) {} {}", nested, offset, ty) + } + Self::IAddImm(i, ty, nested) => { + write!(f, "iadd.{}.{} {}", i, ty, nested) + } + } + } +} + +/// Used to distinguish between top-level global value operations +pub enum Overflow { + Checked, + Unchecked, + Overflowing, + Wrapping, +} +impl fmt::Display for Overflow { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Checked => f.write_str("checked"), + Self::Unchecked => f.write_str("unchecked"), + Self::Overflowing => f.write_str("overflowing"), + Self::Wrapping => f.write_str("wrapping"), + } + } +} + +/// The destination of a branch/jump +pub struct Destination { + pub label: Label, + pub args: Vec, +} +impl Destination { + pub fn new(label: Label, args: Vec) -> Self { + Self { label, args } + } +} +impl fmt::Display for Destination { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.label)?; + if self.args.len() > 0 { + f.write_str(" (")?; + for (i, arg) in self.args.iter().enumerate() { + if i > 0 { + write!(f, ", {}", arg)?; + } else { + write!(f, "{}", arg)?; + } + } + f.write_str(")")?; + } + Ok(()) + } +} + +/// A branch of a switch operation +pub enum SwitchBranch { + Test(u128, Label), + Default(Label), +} +impl fmt::Display for SwitchBranch { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Test(test, label) => { + write!(f, "{} => {}", test, label) + } + Self::Default(label) => { + write!(f, "{}", label) + } + } + } +} diff --git a/hir-parser/src/ast/mod.rs b/hir-parser/src/ast/mod.rs new file mode 100644 index 000000000..35160179b --- /dev/null +++ b/hir-parser/src/ast/mod.rs @@ -0,0 +1,146 @@ +mod block; +mod functions; +mod globals; +mod instruction; +mod types; + +pub use self::block::*; +pub use self::functions::*; +pub use self::globals::*; +pub use self::instruction::*; +pub use self::types::*; + +use std::fmt; + +use miden_diagnostics::{SourceSpan, Span, Spanned}; + +use crate::Symbol; + +/// This represents a fully parsed Miden IR program. +#[derive(Spanned)] +pub struct Program { + #[span] + pub span: SourceSpan, + /// The set of modules in the program + pub modules: Vec, + /// The name of the function that acts as the entry point for the program + pub entry_point: Option, + /// The global variables declared in this program + pub global_vars: Vec, +} +impl Program { + /// Creates a new [Program]. + pub fn new(span: SourceSpan, modules: Vec, globals: Vec) -> Self { + Self { + span: span, + modules: modules, + entry_point: None, + global_vars: globals, + } + } + + pub fn with_entry_point(&mut self, name: FunctionIdentifier) { + self.entry_point = Some(name) + } +} +impl fmt::Display for Program { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for module in self.modules.iter() { + writeln!(f, "{}", module)?; + } + writeln!(f)?; + if self.entry_point.is_some() { + writeln!(f, "{}", self.entry_point.as_ref().unwrap())?; + } + for global in self.global_vars.iter() { + writeln!(f, "{}", global)?; + } + Ok(()) + } +} + +/// This is a type alias used to clarify that an identifier refers to a module +pub type ModuleId = Identifier; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum ModuleType { + /// Kernel context module + Kernel, + /// User context module + Module, +} +impl fmt::Display for ModuleType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Kernel => f.write_str("kernel"), + Self::Module => f.write_str("module"), + } + } +} + +/// This represents the parsed contents of a single Miden IR module +/// +#[derive(Spanned)] +pub struct Module { + #[span] + pub span: SourceSpan, + pub name: ModuleId, + pub ty: ModuleType, + pub functions: Vec, + pub externals: Vec, +} +impl Module { + /// Constructs a new module of the specified type, with the given span, name, functions and exports (externals). + /// + pub fn new( + span: SourceSpan, + ty: ModuleType, + name: ModuleId, + functions: Vec, + externals: Vec, + ) -> Self { + Self { + span, + name, + ty, + functions, + externals, + } + } +} +impl fmt::Display for Module { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + writeln!(f, "{} {}", self.ty, self.name)?; + for func in self.functions.iter() { + writeln!(f, "{}", func)?; + } + for ext in self.externals.iter() { + writeln!(f, "{};", ext)?; + } + Ok(()) + } +} + +/// Represents any type of identifier in Miden IR. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Spanned)] +pub struct Identifier(Span); +impl Identifier { + pub fn new(span: SourceSpan, name: Symbol) -> Self { + Self(Span::new(span, name)) + } + + /// Returns the underlying symbol of the identifier. + pub fn name(&self) -> Symbol { + self.0.item + } + + #[inline] + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} +impl fmt::Display for Identifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", &self.0) + } +} diff --git a/hir-parser/src/ast/types.rs b/hir-parser/src/ast/types.rs new file mode 100644 index 000000000..1c6d6d02c --- /dev/null +++ b/hir-parser/src/ast/types.rs @@ -0,0 +1,90 @@ +use super::*; + +/// The types of values which can be represented in an AirScript program +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Type { + /// The singleton type + Unit, + /// The empty type + Never, + /// The type of a single bit, i.e., the boolean type + I1, + /// Signed 8-bit integers + I8, + /// Unsigned 8-bit integers + U8, + /// Signed 16-bit integers + I16, + /// Unsigned 16-bit integers + U16, + /// Signed 32-bit integers + I32, + /// Unsigned 32-bit integers + U32, + /// Signed 64-bit integers + I64, + /// Unsigned 64-bit integers + U64, + /// Signed 128-bit integers + I128, + /// Unsigned 128-bit integers + U128, + /// Unsigned 256-bit integers + U256, + /// Signed integers of size equal to the native architecture word size + ISize, + /// Unsigned integers of size equal to the native architecture word size + USize, + /// 64-bit floats + F64, + /// Field elements + Felt, + /// Pointers to values of the inner type + Ptr(Box), + /// Native pointers to values of the inner type + NativePtr(Box), + /// Structs containing field values of the specified types in the specified order. + /// The empty struct is a legal type. + Struct(Vec), + /// Arrays of the specified length, containing values of the specified type. + Array(Box, u128), +} +impl fmt::Display for Type { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Unit => f.write_str("()"), + Self::Never => f.write_str("!"), + Self::I1 => f.write_str("i1"), + Self::I8 => f.write_str("i8"), + Self::U8 => f.write_str("u8"), + Self::I16 => f.write_str("i16"), + Self::U16 => f.write_str("u16"), + Self::I32 => f.write_str("i32"), + Self::U32 => f.write_str("u32"), + Self::I64 => f.write_str("i64"), + Self::U64 => f.write_str("u64"), + Self::I128 => f.write_str("i128"), + Self::U128 => f.write_str("u128"), + Self::U256 => f.write_str("u256"), + Self::ISize => f.write_str("isize"), + Self::USize => f.write_str("usize"), + Self::F64 => f.write_str("f64"), + Self::Felt => f.write_str("felt"), + Self::Ptr(inner) => write!(f, "*mut {}", inner), + Self::NativePtr(inner) => write!(f, "&mut {}", inner), + Self::Struct(types) => { + f.write_str("{ ")?; + for (i, t) in types.iter().enumerate() { + if i != 0 { + write!(f, ", {}", t)?; + } else { + write!(f, "{}", t)?; + } + f.write_str(" }")?; + } + Ok(()) + } + Self::Array(inner, length) => write!(f, "[ {} ; {} ]", inner, length), + } + } +} diff --git a/hir-parser/src/lexer/mod.rs b/hir-parser/src/lexer/mod.rs new file mode 100644 index 000000000..e43a48e34 --- /dev/null +++ b/hir-parser/src/lexer/mod.rs @@ -0,0 +1,970 @@ +use core::{fmt, mem, num::IntErrorKind}; + +use miden_diagnostics::{Diagnostic, SourceIndex, SourceSpan, ToDiagnostic}; +use miden_parsing::{Scanner, Source}; + +use crate::{parser::ParseError, Symbol}; + +/// The value produced by the Lexer when iterated +pub type Lexed = Result<(SourceIndex, Token, SourceIndex), ParseError>; + +/// Errors that may occur during lexing of the source +#[derive(Clone, Debug, thiserror::Error)] +pub enum LexicalError { + #[error("invalid integer value: {}", DisplayIntErrorKind(reason))] + InvalidInt { + span: SourceSpan, + reason: IntErrorKind, + }, + #[error("encountered unexpected character '{found}'")] + UnexpectedCharacter { start: SourceIndex, found: char }, +} +impl PartialEq for LexicalError { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::InvalidInt { reason: lhs, .. }, Self::InvalidInt { reason: rhs, .. }) => { + lhs == rhs + } + ( + Self::UnexpectedCharacter { found: lhs, .. }, + Self::UnexpectedCharacter { found: rhs, .. }, + ) => lhs == rhs, + _ => false, + } + } +} +impl ToDiagnostic for LexicalError { + fn to_diagnostic(self) -> Diagnostic { + use miden_diagnostics::Label; + + match self { + Self::InvalidInt { span, ref reason } => Diagnostic::error() + .with_message("invalid integer literal") + .with_labels(vec![Label::primary(span.source_id(), span) + .with_message(format!("{}", DisplayIntErrorKind(reason)))]), + Self::UnexpectedCharacter { start, .. } => Diagnostic::error() + .with_message("unexpected character") + .with_labels(vec![Label::primary( + start.source_id(), + SourceSpan::new(start, start), + )]), + } + } +} + +struct DisplayIntErrorKind<'a>(&'a IntErrorKind); +impl<'a> fmt::Display for DisplayIntErrorKind<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + IntErrorKind::Empty => write!(f, "unable to parse empty string as integer"), + IntErrorKind::InvalidDigit => write!(f, "invalid digit"), + IntErrorKind::PosOverflow => write!(f, "value is too big"), + IntErrorKind::NegOverflow => write!(f, "value is too big"), + IntErrorKind::Zero => write!(f, "zero is not a valid value here"), + other => write!(f, "unable to parse integer value: {:?}", other), + } + } +} + +#[derive(Debug, Clone)] +pub enum Token { + Eof, + Error(LexicalError), + Comment, + // PRIMITIVES + // -------------------------------------------------------------------------------------------- + /// Identifiers should start with alphabet followed by one or more alpha numeric characters + /// or an underscore. + Ident(Symbol), + /// Integers should only contain numeric characters. + Num(u128), + /// Hex strings are used to initialize global variables + Hex(Vec), + + // DECLARATION KEYWORDS + // -------------------------------------------------------------------------------------------- + /// Used to declare kernel modules. Also used to declare a function with kernel calling convention. + Kernel, + /// Used to declare normal modules. + Module, + /// Used to declare a global variable with internal linkage. + Internal, + /// Used to declare a global variable with "one definition rule" linkage. + Odr, + /// Used to declare a global variable with external linkage. + External, + /// Keyword to declare that a function is publicly visible. + Pub, + /// Keyword to declare that a function is publicly visible. + Fn, + /// Keyword to declare a function's calling convention. + Cc, + /// Keyword to declare that a function uses fast calling convention. + Fast, + /// Keyword to declare that a function parameter is a struct return + Sret, + /// Keyword to declare that a function parameter is extended with 0s when filling up a word + /// Also used as an operation to pad a value with 0s. + Zext, + /// Keyword to declare that a function parameter is extended with sign bits when filling up a word + /// Also used as an operation to pad a value with sign bits. + Sext, + + // OPERATION KEYWORDS + // -------------------------------------------------------------------------------------------- + /// Keyword to return from a function + Ret, + /// Keyword to call a function in user space + Call, + /// Keyword to call a function in kernel space + SysCall, + /// Keyword to perform a conditional jump + Cond, + /// Keyword to perform an unconditional jump + Branch, + /// Keyword to perform a multi-branch conditional jump + Switch, + /// Keyword to test whether a value has a specific type + Test, + /// Keyword to load a value from memory. Also used for the load operation on globals + Load, + /// Keyword to copy data from one memory location to another + MemCpy, + /// Keyword to indicate a sequence of assembly instructions + InlineAsm, + /// Keyword to indicate a memory management operation + Memory, + /// Keyword to indicate that the currently assigned amount of memory should grow + Grow, + /// Keyword to perform an addition + Add, + /// Keyword to perform a subtraction + Sub, + /// Keyword to perform a multiplication + Mul, + /// Keyword to perform a division + Div, + /// Keyword to determine a minimum value + Min, + /// Keyword to determine a maximum value + Max, + /// Keyword to perform a modulo + Mod, + /// Keyword to perform a division modulo 2^32 + DivMod, + /// Keyword to perform an exponentiation + Exp, + /// Keyword to perform a boolean and + And, + /// Keyword to perform a bitwise and + BAnd, + /// Keyword to perform a boolean or + Or, + /// Keyword to perform a bitwise or + BOr, + /// Keyword to perform a boolean xor + Xor, + /// Keyword to perform a bitwise xor + BXor, + /// Keyword to perform a left shift + Shl, + /// Keyword to perform a right shift + Shr, + /// Keyword to perform a left rotation + Rotl, + /// Keyword to perform a right rotation + Rotr, + /// Keyword to test for equality + Eq, + /// Keyword to test for inequality + Neq, + /// Keyword to test for greater-than + Gt, + /// Keyword to test for greater-than-or-equal + Gte, + /// Keyword to test for less-than + Lt, + /// Keyword to test for less-than-or-equal + Lte, + /// Keyword to perform a store + Store, + /// Keyword to perform an addition with an immediate parameter + AddImm, + /// Keyword to perform a subtraction with an immediate parameter + SubImm, + /// Keyword to perform a multiplication with an immediate parameter + MulImm, + /// Keyword to perform a division with an immediate parameter + DivImm, + /// Keyword to determine a minimum with an immediate parameter + MinImm, + /// Keyword to determine a maximum with an immediate parameter + MaxImm, + /// Keyword to perform a modulo with an immediate parameter + ModImm, + /// Keyword to perform a division modulo 2^32 with an immediate parameter + DivModImm, + /// Keyword to perform an exponentiation with an immediate parameter + ExpImm, + /// Keyword to perform a boolaen and with an immediate parameter + AndImm, + /// Keyword to perform a bitwise and with an immediate parameter + BAndImm, + /// Keyword to perform a boolean or with an immediate parameter + OrImm, + /// Keyword to perform a bitwise or with an immediate parameter + BOrImm, + /// Keyword to perform a boolean xor with an immediate parameter + XorImm, + /// Keyword to perform a bitwise xor with an immediate parameter + BXorImm, + /// Keyword to perform a left shift with an immediate parameter + ShlImm, + /// Keyword to perform a right shift with an immediate parameter + ShrImm, + /// Keyword to perform a left rotation with an immediate parameter + RotlImm, + /// Keyword to perform a right rotation with an immediate parameter + RotrImm, + /// Keyword to perform an inversion within the field + Inv, + /// Keyword to perform an increment + Incr, + /// Keyword to perform a power-of-2 operation + Pow2, + /// Keyword to perform a boolean negation + Not, + /// Keyword to perform a bitwise negation + BNot, + /// Keyword to count the number of set bits in a value + PopCnt, + /// Keyword to check if a value is odd + IsOdd, + /// Keyword to perform a type cast + Cast, + /// Keyword to cast a pointer to an integer + PtrToInt, + /// Keyword to cast an integer to a pointer + IntToPtr, + /// Keyword to truncate a word + TruncW, + /// Keyword to perform a numerical negation + Neg, + /// Keyword to indicate an immediate unary operation (used alongside the type of the immediate) + Const, + /// Keyword to access elements in a struct + Select, + /// Keyword to perform an assertion + Assert, + /// Keyword to perform an 0-check assertion + Assertz, + /// Keyword to allocate an array + Alloca, + /// Keyword to indicate an unreachable part of the code + Unreachable, + /// Keyword used to indicate a global variable operation + Global, + /// Keyword used for type casts in global variable operations + As, + /// Keyword used to indicate the symbol global variable operation + Symbol, + /// Keyword used to indicate the iadd global variable operation + IAdd, + /// Keyword to indicated an unchecked aritmetic operation + Unchecked, + /// Keyword to indicated a checked aritmetic operation + Checked, + /// Keyword to indicated a wrapping aritmetic operation + Wrapping, + /// Keyword to indicated an overflowing aritmetic operation + Overflowing, + + // TYPES + // -------------------------------------------------------------------------------------------- + I1, + I8, + U8, + I16, + U16, + I32, + U32, + I64, + U64, + I128, + U128, + U256, + ISize, + USize, + F64, + Felt, + Mut, + + // PUNCTUATION + // -------------------------------------------------------------------------------------------- + DoubleQuote, + Colon, + ColonColon, + Semicolon, + Comma, + Dot, + LParen, + RParen, + LBracket, + RBracket, + LBrace, + RBrace, + Equal, + RDoubleArrow, + Plus, + Minus, + RArrow, + Star, + Ampersand, + Bang, + At, +} +impl Token { + pub fn from_keyword_or_ident(s: &str) -> Self { + match s { + "kernel" => Self::Kernel, + "module" => Self::Module, + "internal" => Self::Internal, + "odr" => Self::Odr, + "external" => Self::External, + "pub" => Self::Pub, + "cc" => Self::Cc, + "fast" => Self::Fast, + "sret" => Self::Sret, + "zext" => Self::Zext, + "sext" => Self::Sext, + "ret" => Self::Ret, + "call" => Self::Call, + "syscall" => Self::SysCall, + "cond" => Self::Cond, + "branch" => Self::Branch, + "switch" => Self::Switch, + "test" => Self::Test, + "load" => Self::Load, + "memcpy" => Self::MemCpy, + "inlineasm" => Self::InlineAsm, + "memory" => Self::Memory, + "grow" => Self::Grow, + "add" => Self::Add, + "sub" => Self::Sub, + "mul" => Self::Mul, + "div" => Self::Div, + "min" => Self::Min, + "max" => Self::Max, + "mod" => Self::Mod, + "divmod" => Self::DivMod, + "exp" => Self::Exp, + "and" => Self::And, + "band" => Self::BAnd, + "or" => Self::Or, + "bor" => Self::BOr, + "xor" => Self::Xor, + "bxor" => Self::BXor, + "shl" => Self::Shl, + "shr" => Self::Shr, + "rotl" => Self::Rotl, + "rotr" => Self::Rotr, + "eq" => Self::Eq, + "neq" => Self::Neq, + "gt" => Self::Gt, + "gte" => Self::Gte, + "lt" => Self::Lt, + "lte" => Self::Lte, + "store" => Self::Store, + "add_imm" => Self::AddImm, + "sub_imm" => Self::SubImm, + "mul_imm" => Self::MulImm, + "div_imm" => Self::DivImm, + "min_imm" => Self::MinImm, + "max_imm" => Self::MaxImm, + "mod_imm" => Self::ModImm, + "divmod_imm" => Self::DivModImm, + "exp_imm" => Self::ExpImm, + "and_imm" => Self::AndImm, + "band_imm" => Self::BAndImm, + "or_imm" => Self::OrImm, + "bor_imm" => Self::BOrImm, + "xor_imm" => Self::XorImm, + "bxor_imm" => Self::BXorImm, + "shl_imm" => Self::ShlImm, + "shr_imm" => Self::ShrImm, + "rotl_imm" => Self::RotlImm, + "rotr_imm" => Self::RotrImm, + "inv" => Self::Inv, + "incr" => Self::Incr, + "pow2" => Self::Pow2, + "not" => Self::Not, + "bnot" => Self::BNot, + "popcnt" => Self::PopCnt, + "is_odd" => Self::IsOdd, + "cast" => Self::Cast, + "ptrtoint" => Self::PtrToInt, + "inttoprt" => Self::IntToPtr, + "truncw" => Self::TruncW, + "neg" => Self::Neg, + "const" => Self::Const, + "select" => Self::Select, + "assert" => Self::Assert, + "assertz" => Self::Assertz, + "alloca" => Self::Alloca, + "unreachable" => Self::Unreachable, + "as" => Self::As, + "global" => Self::Global, + "symbol" => Self::Symbol, + "iadd" => Self::IAdd, + "unchecked" => Self::Unchecked, + "checked" => Self::Checked, + "wrapping" => Self::Wrapping, + "overflowing" => Self::Overflowing, + "i1" => Self::I1, + "i8" => Self::I8, + "u8" => Self::U8, + "i16" => Self::I16, + "u16" => Self::U16, + "i32" => Self::I32, + "u32" => Self::U32, + "i64" => Self::I64, + "u64" => Self::U64, + "i128" => Self::I128, + "u128" => Self::U128, + "u256" => Self::U256, + "isize" => Self::ISize, + "usize" => Self::USize, + "f64" => Self::F64, + "felt" => Self::Felt, + "mut" => Self::Mut, + other => Self::Ident(Symbol::intern(other)), + } + } +} +impl Eq for Token {} +impl PartialEq for Token { + fn eq(&self, other: &Token) -> bool { + match self { + Self::Num(i) => { + if let Self::Num(i2) = other { + return *i == *i2; + } + } + Self::Error(_) => { + if let Self::Error(_) = other { + return true; + } + } + Self::Ident(i) => { + if let Self::Ident(i2) = other { + return i == i2; + } + } + _ => return mem::discriminant(self) == mem::discriminant(other), + } + false + } +} +impl fmt::Display for Token { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Eof => write!(f, "EOF"), + Self::Error(_) => write!(f, "ERROR"), + Self::Comment => write!(f, "COMMENT"), + Self::Ident(ref id) => write!(f, "{}", id), + Self::Num(ref i) => write!(f, "{}", i), + Self::Hex(ref data) => { + write!(f, "0x")?; + for i in data.iter().rev() { + write!(f, "{:02x}", i)?; + } + Ok(()) + } + Self::Kernel => write!(f, "kernel"), + Self::Module => write!(f, "module"), + Self::Internal => write!(f, "internal"), + Self::Odr => write!(f, "odr"), + Self::External => write!(f, "external"), + Self::Pub => write!(f, "pub"), + Self::Fn => write!(f, "fn"), + Self::Cc => write!(f, "cc"), + Self::Fast => write!(f, "fast"), + Self::Sret => write!(f, "sret"), + Self::Zext => write!(f, "zext"), + Self::Sext => write!(f, "sext"), + Self::Ret => write!(f, "ret"), + Self::Call => write!(f, "call"), + Self::SysCall => write!(f, "syscall"), + Self::Cond => write!(f, "cond"), + Self::Branch => write!(f, "branch"), + Self::Switch => write!(f, "switch"), + Self::Test => write!(f, "test"), + Self::Load => write!(f, "load"), + Self::MemCpy => write!(f, "memcpy"), + Self::InlineAsm => write!(f, "inlineasm"), + Self::Memory => write!(f, "memory"), + Self::Grow => write!(f, "grow"), + Self::Add => write!(f, "add"), + Self::Sub => write!(f, "sub"), + Self::Mul => write!(f, "mul"), + Self::Div => write!(f, "div"), + Self::Min => write!(f, "min"), + Self::Max => write!(f, "max"), + Self::Mod => write!(f, "mod"), + Self::DivMod => write!(f, "divmod"), + Self::Exp => write!(f, "exp"), + Self::And => write!(f, "and"), + Self::BAnd => write!(f, "band"), + Self::Or => write!(f, "or"), + Self::BOr => write!(f, "bor"), + Self::Xor => write!(f, "xor"), + Self::BXor => write!(f, "bxor"), + Self::Shl => write!(f, "shl"), + Self::Shr => write!(f, "shr"), + Self::Rotl => write!(f, "rotl"), + Self::Rotr => write!(f, "rotr"), + Self::Eq => write!(f, "eq"), + Self::Neq => write!(f, "neq"), + Self::Gt => write!(f, "gt"), + Self::Gte => write!(f, "gte"), + Self::Lt => write!(f, "lt"), + Self::Lte => write!(f, "lte"), + Self::Store => write!(f, "store"), + Self::AddImm => write!(f, "add_imm"), + Self::SubImm => write!(f, "sub_imm"), + Self::MulImm => write!(f, "mul_imm"), + Self::DivImm => write!(f, "div_imm"), + Self::MinImm => write!(f, "min_imm"), + Self::MaxImm => write!(f, "max_imm"), + Self::ModImm => write!(f, "mod_imm"), + Self::DivModImm => write!(f, "divmod_imm"), + Self::ExpImm => write!(f, "exp_imm"), + Self::AndImm => write!(f, "and_imm"), + Self::BAndImm => write!(f, "band_imm"), + Self::OrImm => write!(f, "or_imm"), + Self::BOrImm => write!(f, "bor_imm"), + Self::XorImm => write!(f, "xor_imm"), + Self::BXorImm => write!(f, "bxor_imm"), + Self::ShlImm => write!(f, "shl_imm"), + Self::ShrImm => write!(f, "shr_imm"), + Self::RotlImm => write!(f, "rotl_imm"), + Self::RotrImm => write!(f, "rotr_imm"), + Self::Inv => write!(f, "inv"), + Self::Incr => write!(f, "incr"), + Self::Pow2 => write!(f, "pow2"), + Self::Not => write!(f, "not"), + Self::BNot => write!(f, "bnot"), + Self::PopCnt => write!(f, "popcnt"), + Self::IsOdd => write!(f, "is_odd"), + Self::Cast => write!(f, "cast"), + Self::PtrToInt => write!(f, "ptrtoint"), + Self::IntToPtr => write!(f, "inttoptr"), + Self::TruncW => write!(f, "truncw"), + Self::Neg => write!(f, "neg"), + Self::Const => write!(f, "const"), + Self::Select => write!(f, "select"), + Self::Assert => write!(f, "assert"), + Self::Assertz => write!(f, "assertz"), + Self::Alloca => write!(f, "alloca"), + Self::Unreachable => write!(f, "unreachable"), + Self::Global => write!(f, "global"), + Self::As => write!(f, "as"), + Self::Symbol => write!(f, "symbol"), + Self::IAdd => write!(f, "iadd"), + Self::Unchecked => write!(f, "unchecked"), + Self::Checked => write!(f, "checked"), + Self::Wrapping => write!(f, "wrapping"), + Self::Overflowing => write!(f, "overflowing"), + Self::I1 => write!(f, "i1"), + Self::I8 => write!(f, "i8"), + Self::U8 => write!(f, "u8"), + Self::I16 => write!(f, "i16"), + Self::U16 => write!(f, "u16"), + Self::I32 => write!(f, "i32"), + Self::U32 => write!(f, "u32"), + Self::I64 => write!(f, "i64"), + Self::U64 => write!(f, "u64"), + Self::I128 => write!(f, "i128"), + Self::U128 => write!(f, "u128"), + Self::U256 => write!(f, "u256"), + Self::ISize => write!(f, "isize"), + Self::USize => write!(f, "usize"), + Self::F64 => write!(f, "f64"), + Self::Felt => write!(f, "felt"), + Self::Mut => write!(f, "mut"), + Self::DoubleQuote => write!(f, "\""), + Self::Colon => write!(f, ":"), + Self::ColonColon => write!(f, "::"), + Self::Semicolon => write!(f, ";"), + Self::Comma => write!(f, ","), + Self::Dot => write!(f, "."), + Self::LParen => write!(f, "("), + Self::RParen => write!(f, ")"), + Self::LBracket => write!(f, "["), + Self::RBracket => write!(f, "]"), + Self::LBrace => write!(f, "{{"), + Self::RBrace => write!(f, "}}"), + Self::Equal => write!(f, "="), + Self::RDoubleArrow => write!(f, "=>"), + Self::Plus => write!(f, "+"), + Self::Minus => write!(f, "-"), + Self::RArrow => write!(f, "->"), + Self::Star => write!(f, "*"), + Self::Ampersand => write!(f, "&"), + Self::Bang => write!(f, "!"), + Self::At => write!(f, "@"), + } + } +} + +macro_rules! pop { + ($lex:ident) => {{ + $lex.skip(); + }}; + ($lex:ident, $code:expr) => {{ + $lex.skip(); + $code + }}; +} + +macro_rules! pop2 { + ($lex:ident) => {{ + $lex.skip(); + $lex.skip(); + }}; + ($lex:ident, $code:expr) => {{ + $lex.skip(); + $lex.skip(); + $code + }}; +} + +/// The lexer that is used to perform lexical analysis on the Miden IR grammar. The lexer implements +/// the `Iterator` trait, so in order to retrieve the tokens, you simply have to iterate over it. +/// +/// # Errors +/// +/// Because the lexer is implemented as an iterator over tokens, this means that you can continue +/// to get tokens even if a lexical error occurs. The lexer will attempt to recover from an error +/// by injecting tokens it expects. +/// +/// If an error is unrecoverable, the lexer will continue to produce tokens, but there is no +/// guarantee that parsing them will produce meaningful results, it is primarily to assist in +/// gathering as many errors as possible. +pub struct Lexer { + /// The scanner produces a sequence of chars + location, and can be controlled + /// The location type is SourceIndex + scanner: Scanner, + + /// The most recent token to be lexed. + /// At the start and end, this should be Token::Eof + token: Token, + + /// The position in the input where the current token starts + /// At the start this will be the byte index of the beginning of the input + token_start: SourceIndex, + + /// The position in the input where the current token ends + /// At the start this will be the byte index of the beginning of the input + token_end: SourceIndex, + + /// When we have reached true Eof, this gets set to true, and the only token + /// produced after that point is Token::Eof, or None, depending on how you are + /// consuming the lexer + eof: bool, +} +impl Lexer +where + S: Source, +{ + /// Produces an instance of the lexer with the lexical analysis to be performed on the `input` + /// string. Note that no lexical analysis occurs until the lexer has been iterated over. + pub fn new(scanner: Scanner) -> Self { + use miden_diagnostics::ByteOffset; + + let start = scanner.start(); + let mut lexer = Lexer { + scanner, + token: Token::Eof, + token_start: start + ByteOffset(0), + token_end: start + ByteOffset(0), + eof: false, + }; + lexer.advance(); + lexer + } + + pub fn lex(&mut self) -> Option<::Item> { + if self.eof && self.token == Token::Eof { + return None; + } + + let token = std::mem::replace(&mut self.token, Token::Eof); + let start = self.token_start; + let end = self.token_end; + self.advance(); + match token { + Token::Error(err) => Some(Err(err.into())), + token => Some(Ok((start, token, end))), + } + } + + fn advance(&mut self) { + self.advance_start(); + self.token = self.tokenize(); + } + + #[inline] + fn advance_start(&mut self) { + let mut position: SourceIndex; + loop { + let (pos, c) = self.scanner.read(); + + position = pos; + + if c == '\0' { + self.eof = true; + return; + } + + if c.is_whitespace() { + self.scanner.advance(); + continue; + } + + break; + } + + self.token_start = position; + } + + #[inline] + fn pop(&mut self) -> char { + use miden_diagnostics::ByteOffset; + + let (pos, c) = self.scanner.pop(); + self.token_end = pos + ByteOffset::from_char_len(c); + c + } + + #[inline] + fn peek(&mut self) -> char { + let (_, c) = self.scanner.peek(); + c + } + + #[inline] + fn read(&mut self) -> char { + let (_, c) = self.scanner.read(); + c + } + + #[inline] + fn skip(&mut self) { + self.pop(); + } + + /// Get the span for the current token in `Source`. + #[inline] + fn span(&self) -> SourceSpan { + SourceSpan::new(self.token_start, self.token_end) + } + + /// Get a string slice of the current token. + #[inline] + fn slice(&self) -> &str { + self.scanner.slice(self.span()) + } + + #[inline] + fn skip_whitespace(&mut self) { + let mut c: char; + loop { + c = self.read(); + + if !c.is_whitespace() { + break; + } + + self.skip(); + } + } + + fn tokenize(&mut self) -> Token { + let c = self.read(); + + if c == '\\' { + match self.peek() { + '\\' => { + self.skip(); + self.skip(); + self.lex_comment() + } + _ => Token::Error(LexicalError::UnexpectedCharacter { + start: self.span().start(), + found: c, + }), + }; + } + + if c == '\0' { + self.eof = true; + return Token::Eof; + } + + if c.is_whitespace() { + self.skip_whitespace(); + } + + match self.read() { + ',' => pop!(self, Token::Comma), + '.' => pop!(self, Token::Dot), + ':' => match self.peek() { + ':' => pop2!(self, Token::ColonColon), + _ => pop!(self, Token::Colon), + }, + '"' => pop!(self, Token::DoubleQuote), + '(' => pop!(self, Token::LParen), + ')' => pop!(self, Token::RParen), + '[' => pop!(self, Token::LBracket), + ']' => pop!(self, Token::RBracket), + '{' => pop!(self, Token::LBrace), + '}' => pop!(self, Token::RBrace), + '=' => match self.peek() { + '>' => pop2!(self, Token::RDoubleArrow), + _ => pop!(self, Token::Equal), + }, + '+' => pop!(self, Token::Plus), + '-' => match self.peek() { + '>' => pop2!(self, Token::RArrow), + _ => pop!(self, Token::Minus), + }, + '*' => pop!(self, Token::Star), + '&' => pop!(self, Token::Ampersand), + '!' => pop!(self, Token::Bang), + '@' => pop!(self, Token::At), + '0' => match self.peek() { + 'x' => { + self.skip(); + self.skip(); + self.lex_hex() + } + '0'..='9' => self.lex_number(), + _ => Token::Error(LexicalError::UnexpectedCharacter { + start: self.span().start(), + found: c, + }), + }, + '1'..='9' => self.lex_number(), + 'a'..='z' => self.lex_keyword_or_ident(), + 'A'..='Z' => self.lex_identifier(), + c => Token::Error(LexicalError::UnexpectedCharacter { + start: self.span().start(), + found: c, + }), + } + } + + fn lex_comment(&mut self) -> Token { + let mut c; + loop { + c = self.read(); + + if c == '\n' { + break; + } + + if c == '\0' { + self.eof = true; + break; + } + + self.skip(); + } + + Token::Comment + } + + #[inline] + fn lex_keyword_or_ident(&mut self) -> Token { + let c = self.pop(); + debug_assert!(c.is_ascii_alphabetic() && c.is_lowercase()); + + self.skip_ident(); + + Token::from_keyword_or_ident(self.slice()) + } + + #[inline] + fn lex_identifier(&mut self) -> Token { + let c = self.pop(); + debug_assert!(c.is_ascii_alphabetic()); + + self.skip_ident(); + Token::Ident(Symbol::intern(self.slice())) + } + + fn skip_ident(&mut self) { + loop { + match self.read() { + '_' => self.skip(), + '0'..='9' => self.skip(), + c if c.is_ascii_alphabetic() => self.skip(), + _ => break, + } + } + } + + #[inline] + fn lex_number(&mut self) -> Token { + let mut num = String::new(); + + // Expect the first character to be a digit + debug_assert!(self.read().is_ascii_digit()); + + while let '0'..='9' = self.read() { + num.push(self.pop()); + } + + match num.parse::() { + Ok(i) => Token::Num(i), + Err(err) => Token::Error(LexicalError::InvalidInt { + span: self.span(), + reason: err.kind().clone(), + }), + } + } + + #[inline] + fn lex_hex(&mut self) -> Token { + let mut res: Vec = Vec::new(); + + loop { + match self.read() { + '0'..='9' | 'a'..='f' | 'A'..='F' => { + res.push(self.pop() as u8); + } + _ => { + break; + } + } + } + + Token::Hex(res) + } +} + +impl Iterator for Lexer +where + S: Source, +{ + type Item = Lexed; + + fn next(&mut self) -> Option { + let mut res = self.lex(); + while let Some(Ok((_, Token::Comment, _))) = res { + res = self.lex(); + } + res + } +} diff --git a/hir-parser/src/lib.rs b/hir-parser/src/lib.rs new file mode 100644 index 000000000..a78424e14 --- /dev/null +++ b/hir-parser/src/lib.rs @@ -0,0 +1,107 @@ +#[macro_use] +extern crate lalrpop_util; + +pub mod ast; +mod lexer; +mod parser; +pub mod symbols; + +pub use self::parser::{ParseError, Parser}; +pub use self::symbols::Symbol; + +use std::path::Path; +use std::sync::Arc; + +use miden_diagnostics::{CodeMap, DiagnosticsHandler}; + +/// Parses the provided source and returns the AST. +pub fn parse( + diagnostics: &DiagnosticsHandler, + codemap: Arc, + source: &str, +) -> Result { + let parser = Parser::new((), codemap); + match parser.parse_string::(diagnostics, source) { + Ok(ast) => Ok(ast), + Err(ParseError::Lexer(err)) => { + diagnostics.emit(err); + Err(ParseError::Failed) + } + Err(err) => Err(err), + } +} + +/// Parses the provided source and returns the AST. +pub fn parse_file>( + diagnostics: &DiagnosticsHandler, + codemap: Arc, + source: P, +) -> Result { + let parser = Parser::new((), codemap); + match parser.parse_file::(diagnostics, source) { + Ok(ast) => Ok(ast), + Err(ParseError::Lexer(err)) => { + diagnostics.emit(err); + Err(ParseError::Failed) + } + Err(err) => Err(err), + } +} + +/// Parses the provided source string with a default [CodeMap] and [DiagnosticsHandler]. +/// +/// This is primarily provided for use in tests, you should generally prefer [parse] +pub fn parse_str(source: &str) -> Result { + use miden_diagnostics::{ + term::termcolor::ColorChoice, DefaultEmitter, DiagnosticsConfig, Verbosity, + }; + + let codemap = Arc::new(CodeMap::new()); + let emitter = Arc::new(DefaultEmitter::new(ColorChoice::Auto)); + let config = DiagnosticsConfig { + verbosity: Verbosity::Warning, + warnings_as_errors: true, + no_warn: false, + display: Default::default(), + }; + let diagnostics = DiagnosticsHandler::new(config, codemap.clone(), emitter); + parse(&diagnostics, codemap, source) +} + +/// Parses a [Module] from the given path. +/// +/// This is primarily intended for use in the import resolution phase. +pub(crate) fn parse_module_from_file>( + diagnostics: &DiagnosticsHandler, + codemap: Arc, + path: P, +) -> Result { + let parser = Parser::new((), codemap); + match parser.parse_file::(diagnostics, path) { + ok @ Ok(_) => ok, + Err(ParseError::Lexer(err)) => { + diagnostics.emit(err); + Err(ParseError::Failed) + } + err @ Err(_) => err, + } +} + +/// Parses a [Module] from a file already in the codemap +/// +/// This is primarily intended for use in the import resolution phase. +pub(crate) fn parse_module( + diagnostics: &DiagnosticsHandler, + codemap: Arc, + source: Arc, +) -> Result { + let parser = Parser::new((), codemap); + match parser.parse::(diagnostics, source) { + ok @ Ok(_) => ok, + Err(ParseError::Lexer(err)) => { + diagnostics.emit(err); + Err(ParseError::Failed) + } + err @ Err(_) => err, + } +} diff --git a/hir-parser/src/parser/grammar.lalrpop b/hir-parser/src/parser/grammar.lalrpop new file mode 100644 index 000000000..c5dc422e5 --- /dev/null +++ b/hir-parser/src/parser/grammar.lalrpop @@ -0,0 +1,757 @@ +use std::sync::Arc; + +use miden_diagnostics::{CodeMap, DiagnosticsHandler}; + +use crate::{ + ast::*, + lexer::Token, + parser::ParseError, + Symbol +}; + +grammar(diagnostics: &DiagnosticsHandler, codemap: &Arc, next_var: &mut usize); + +// MACROS +// ================================================================================================ + +// Comma-delimited with at least one element +Comma: Vec = { + ",")*> => { + let mut v = v; + v.push(e); + v + } +}; + +// ColonColon-delimited with at least one element +ColonColon: Vec = { + "::")*> => { + let mut v = v; + v.push(e); + v + } +}; + +// AST NODE +// ================================================================================================ + +pub Program: Program = { + => { + let mut p = Program::new(span!(l, r), modules, globals); + if let Some(name) = entry { + p.with_entry_point(name); + } + p + } +} + +pub Module: Module = { + "kernel" => { + Module::new(span!(l, r), ModuleType::Kernel, name, functions, externals) + }, + "module" => { + Module::new(span!(l, r), ModuleType::Module, name, functions, externals) + }, +} + +// GLOBALS +// ================================================================================================ + +GlobalVarDeclaration: GlobalVarDeclaration = { + => { + let mut v = GlobalVarDeclaration::new(span!(l, r), name, ty, linkage); + if let Some(e) = init { + v.with_init(e); + } + v + } +} + +Linkage: Linkage = { + "internal" => Linkage::Internal, + "odr" => Linkage::Odr, + "external" => Linkage::Internal, +} + +GlobalVarInitializer: GlobalVarInitializer = { + "=" => { + GlobalVarInitializer::new(e) + } +} + +// TYPES +// ============================================================================================== + +Type: Type = { + "(" ")" => Type::Unit, + "!" => Type::Never, + "i1" => Type::I1, + "i8" => Type::I8, + "u8" => Type::U8, + "i16" => Type::I16, + "u16" => Type::U16, + "i32" => Type::I32, + "u32" => Type::U32, + "i64" => Type::I64, + "u64" => Type::U64, + "i128" => Type::I128, + "u128" => Type::U128, + "u256" => Type::U256, + "isize" => Type::ISize, + "usize" => Type::USize, + "f64" => Type::F64, + "felt" => Type::Felt, + "*" "mut" => Type::Ptr(Box::new(inner)), + "&" "mut" => Type::NativePtr(Box::new(inner)), + "{" > "}" => Type::Struct(field_types), + "{" "}" => Type::Struct(Vec::new()), + "[" ";" "]" => Type::Array(Box::new(inner), length), +} + +// FUNCTIONS +// ============================================================================================== + +ExternalFunction: FunctionSignature = { + ";" => signature +} + +CallConvention: CallConvention = { + "cc" "(" "fast" ")" => CallConvention::Fast, + "cc" "(" "kernel" ")" => CallConvention::Kernel, +} + +ParamPurpose: ParameterPurpose = { + => ParameterPurpose::Standard, + "sret" => ParameterPurpose::Sret +} + +ParamExtension: ParameterExtension = { + "zext" => ParameterExtension::Zero, + "sext" => ParameterExtension::Signed, +} + +FunctionReturn: FunctionReturn = { + => { + let ext = if let Some(e) = extension { e } else { ParameterExtension::None }; + FunctionReturn::new(ext, ty) + } +} + +FunctionReturnSignature: Vec = { + "->" > => returns +} + +FunctionParam: FunctionParameter = { + => { + let ext = if let Some(e) = extension { e } else { ParameterExtension::None }; + FunctionParameter::new(purpose, ext, ty) + } +} + +FunctionParams: Vec = { + "(" ")" => Vec::new(), + "(" > ")" => params, +} + +FunctionSignature: FunctionSignature = { + "pub" "fn" => { + let cc = if let Some(cc) = call_convention { cc } else { CallConvention::Default }; + let ret = if let Some(r) = returns { r } else { Vec::new() }; + FunctionSignature::new(span!(l, r), Visibility::Public, cc, name, params, ret) + }, + "fn" => { + let cc = if let Some(cc) = call_convention { cc } else { CallConvention::Default }; + let ret = if let Some(r) = returns { r } else { Vec::new() }; + FunctionSignature::new(span!(l, r), Visibility::Private, cc, name, params, ret) + }, +} + +FunctionDeclaration: FunctionDeclaration = { + "{" "}" => { + FunctionDeclaration::new(span!(l, r), signature, blocks) + } +} + +// BLOCKS +// ================================================================================================ + +Label: Label = { + => { + Label::new(id) + } +} + +BlockArg: BlockArgument = { + ":" => { + BlockArgument::new(value, ty) + } +} + +BlockArgs: Vec = { + "(" > ")" => args, +} + +BlockHeader: BlockHeader = { + ":" => { + let a = if let Some(args) = arguments { args } else { Vec::new() }; + BlockHeader::new(label, a) + }, +} + +Block: Block = { + "{" "}" => { + Block::new(span!(l, r), header, instructions) + } +} + +// INSTRUCTIONS +// ================================================================================================ + +Overflow: Overflow = { + "." "unchecked" => Overflow::Unchecked, + "." "checked" => Overflow::Checked, + "." "wrapping" => Overflow::Wrapping, + "." "overflowing" => Overflow::Overflowing, +} + +BinaryOpCode: BinaryOpCode = { + "add" => { + BinaryOpCode::Add(overflow) + }, + "sub" => { + BinaryOpCode::Sub(overflow) + }, + "mul" => { + BinaryOpCode::Mul(overflow) + }, + "div" => { + BinaryOpCode::Div(overflow) + }, + "min" => { + BinaryOpCode::Min(overflow) + }, + "max" => { + BinaryOpCode::Max(overflow) + }, + "mod" => { + BinaryOpCode::Mod(overflow) + }, + "divmod" => { + BinaryOpCode::DivMod(overflow) + }, + "exp" => { + BinaryOpCode::Exp(overflow) + }, + "and" => { + BinaryOpCode::And + }, + "band" => { + BinaryOpCode::BAnd(overflow) + }, + "or" => { + BinaryOpCode::Or + }, + "bor" => { + BinaryOpCode::BOr(overflow) + }, + "xor" => { + BinaryOpCode::Xor + }, + "bxor" => { + BinaryOpCode::BXor(overflow) + }, + "shl" => { + BinaryOpCode::Shl(overflow) + }, + "shr" => { + BinaryOpCode::Shr(overflow) + }, + "rotl" => { + BinaryOpCode::Rotl(overflow) + }, + "rotr" => { + BinaryOpCode::Rotr(overflow) + }, + "eq" => { + BinaryOpCode::Eq + }, + "neq" => { + BinaryOpCode::Neq + }, + "gt" => { + BinaryOpCode::Gt + }, + "gte" => { + BinaryOpCode::Gte + }, + "lt" => { + BinaryOpCode::Lt + }, + "lte" => { + BinaryOpCode::Lte + }, + "store" => { + BinaryOpCode::Store + }, +} + +BinaryImmOpCode: BinaryImmOpCode = { + "add_imm" => { + BinaryImmOpCode::AddImm(overflow) + }, + "sub_imm" => { + BinaryImmOpCode::SubImm(overflow) + }, + "mul_imm" => { + BinaryImmOpCode::MulImm(overflow) + }, + "div_imm" => { + BinaryImmOpCode::DivImm(overflow) + }, + "min_imm" => { + BinaryImmOpCode::MinImm(overflow) + }, + "max_imm" => { + BinaryImmOpCode::MaxImm(overflow) + }, + "mod_imm" => { + BinaryImmOpCode::ModImm(overflow) + }, + "divmod_imm" => { + BinaryImmOpCode::DivModImm(overflow) + }, + "exp_imm" => { + BinaryImmOpCode::ExpImm(overflow) + }, + "and_imm" => { + BinaryImmOpCode::AndImm + }, + "band_imm" => { + BinaryImmOpCode::BAndImm(overflow) + }, + "or_imm" => { + BinaryImmOpCode::OrImm + }, + "bor_imm" => { + BinaryImmOpCode::BOrImm(overflow) + }, + "xor_imm" => { + BinaryImmOpCode::XorImm + }, + "bxor_imm" => { + BinaryImmOpCode::BXorImm(overflow) + }, + "shl_imm" => { + BinaryImmOpCode::ShlImm(overflow) + }, + "shr_imm" => { + BinaryImmOpCode::ShrImm(overflow) + }, + "rotl_imm" => { + BinaryImmOpCode::RotlImm(overflow) + }, + "rotr_imm" => { + BinaryImmOpCode::RotrImm(overflow) + }, +} + +UnaryOpCode: UnaryOpCode = { + "inv" => { + UnaryOpCode::Inv + }, + "incr" => { + UnaryOpCode::Incr + }, + "pow2" => { + UnaryOpCode::Pow2 + }, + "not" => { + UnaryOpCode::Not + }, + "bnot" => { + UnaryOpCode::BNot + }, + "popcnt" => { + UnaryOpCode::PopCnt + }, + "is_odd" => { + UnaryOpCode::IsOdd + }, + "cast" => { + UnaryOpCode::Cast + }, + "ptrtoint" => { + UnaryOpCode::PtrToInt + }, + "inttoprt" => { + UnaryOpCode::IntToPtr + }, + "truncw" => { + UnaryOpCode::TruncW + }, + "zext" => { + UnaryOpCode::Zext + }, + "sext" => { + UnaryOpCode::Sext + }, + "neg" => { + UnaryOpCode::Neg + }, +} + +UnaryImmOpCode: UnaryImmOpCode = { + "const" "." "i1" => UnaryImmOpCode::I1, + "const" "." "i8" => UnaryImmOpCode::I8, + "const" "." "i16" => UnaryImmOpCode::I16, + "const" "." "i32" => UnaryImmOpCode::I32, + "const" "." "i64" => UnaryImmOpCode::I64, + "const" "." "isize" => UnaryImmOpCode::ISize, + "const" "." "felt" => UnaryImmOpCode::Felt, + "const" "." "f64" => UnaryImmOpCode::F64, +} + +Offset: Offset = { + "+" => { + Offset::Pos(val) + }, + "-" => { + Offset::Neg(val) + } +} + +GlobalValueOperationNested: GlobalValueOpNested = { + "@" => { + if let Some(o) = offset { + GlobalValueOpNested::Symbol(id, o) + } + else { + GlobalValueOpNested::Symbol(id, Offset::Pos(0)) + } + }, + "*" => { + GlobalValueOpNested::Load(Box::new(nested), Offset::Pos(0)) + }, + "*" "(" ")" => { + GlobalValueOpNested::Load(Box::new(nested), offset) + }, + "*" "(" ")" "as" => { + if let Some(o) = offset { + GlobalValueOpNested::Cast(Box::new(nested), o, ty) + } + else { + GlobalValueOpNested::Cast(Box::new(nested), Offset::Pos(0), ty) + } + }, +} + +GlobalValueOperation: GlobalValueOp = { + "global" "." "symbol" "@" => { + if let Some(o) = offset { + GlobalValueOp::Symbol(id, o) + } + else { + GlobalValueOp::Symbol(id, Offset::Pos(0)) + } + }, + "global" "." "load" => { + GlobalValueOp::Load(nested, Offset::Pos(0)) + }, + "global" "." "load" "(" ")" => { + GlobalValueOp::Load(nested, offset) + }, + "global" "." "load" "(" ")" "as" => { + if let Some(o) = offset { + GlobalValueOp::Cast(nested, o, ty) + } + else { + GlobalValueOp::Cast(nested, Offset::Pos(0), ty) + } + }, + "global" "." "iadd" "." "." => { + GlobalValueOp::IAddImm(number, ty, nested) + }, +} + +CallOp: CallOp = { + "call" => CallOp::Call, + "syscall" => CallOp::SysCall, +} + +SwitchBranch: SwitchBranch = { + "=>" => { + SwitchBranch::Test(value, label) + }, + => { + SwitchBranch::Default(label) + } +} + +Destination: Destination = { + => { + let a = if let Some(args) = arguments { args } else { Vec::new() }; + Destination::new(label, a) + }, +} + +Operation: Operation = { + => { + Operation::BinaryOp(op, val1, val2) + }, + => { + Operation::BinaryImmOp(op, val, imm) + }, + => { + Operation::UnaryOp(op, val) + }, + => { + Operation::UnaryImmOp(op, imm) + }, + "ret" "(" > ")" => { + Operation::ReturnOp(vals) + }, + "ret" => { + Operation::ReturnOp(Vec::new()) + }, + "(" > ")" => { + Operation::CallOp(op, f, args) + }, + "(" ")" => { + Operation::CallOp(op, f, Vec::new()) + }, + "cond" "," "," => { + Operation::CondOp(val, dest1, dest2) + }, + "branch" => { + Operation::BranchOp(dest) + }, + "switch" "," > => { + Operation::SwitchOp(val, branches) + }, + "test" "." => { + Operation::TestOp(ty, val) + }, + "select" "," "," => { + let args = vec![cond, a, b]; + Operation::PrimOp(PrimOpCode::Select, args) + }, + "assert" => { + let args = vec![val]; + Operation::PrimOp(PrimOpCode::Assert, args) + }, + "assertz" => { + let args = vec![val]; + Operation::PrimOp(PrimOpCode::Assertz, args) + }, + "assert" "." "eq" "," => { + let args = vec![lhs, rhs]; + Operation::PrimOp(PrimOpCode::AssertEq, args) + }, + "alloca" => { + Operation::PrimOp(PrimOpCode::Alloca, Vec::new()) + }, + "unreachable" => { + Operation::PrimOp(PrimOpCode::Unreachable, Vec::new()) + }, + "load" => { + Operation::LoadOp(val) + }, + "memcpy" "." "," "," => { + Operation::MemCpyOp(ty, val1, val2, val3) + }, +// TODO: Inline assembly +// "inlineasm" "\"" "\"" "," > => ..., +// "inlineasm" "\"" "\"" "," => ..., + => { + Operation::GlobalValueOp(op) + } +// TODO: MemGrow +// "memory" "." "grow" => ..., +} + +Instruction: Instruction = { + > "=" ":" > => { + Instruction::new(span!(l, r), values, op, types) + }, + => { + Instruction::new(span!(l, r), Vec::new(), op, Vec::new()) + }, +} + + +// VALUES AND IDENTIFIERS +// ================================================================================================ + +HexString: Vec = { + hex, +} + +Number: u128 = { + int, +} + +Immediate: Immediate = { + => Immediate::Pos(val), + "-" => Immediate::Neg(val), +} + +Identifier: Identifier = { + => Identifier::new(span!(l, r), name) +} + +Value: Value = { + => Value::new(id) +} + +FunctionIdentifier: FunctionIdentifier = { + > => FunctionIdentifier::new(span!(l, r), names) +} + + + +// LEXER +// ================================================================================================ + +extern { + type Error = ParseError; + type Location = miden_diagnostics::SourceIndex; + + enum Token { + identifier => Token::Ident(), + int => Token::Num(), + hex => Token::Hex(>), + "kernel" => Token::Kernel, + "module" => Token::Module, + "internal" => Token::Internal, + "odr" => Token::Odr, + "external" => Token::External, + "pub" => Token::Pub, + "fn" => Token::Fn, + "cc" => Token::Cc, + "fast" => Token::Fast, + "sret" => Token::Sret, + "zext" => Token::Zext, + "sext" => Token::Sext, + "ret" => Token::Ret, + "call" => Token::Call, + "syscall" => Token::SysCall, + "cond" => Token::Cond, + "branch" => Token::Branch, + "switch" => Token::Switch, + "test" => Token::Test, + "load" => Token::Load, + "memcpy" => Token::MemCpy, + "inlineasm" => Token::InlineAsm, + "memory" => Token::Memory, + "grow" => Token::Grow, + "add" => Token::Add, + "sub" => Token::Sub, + "mul" => Token::Mul, + "div" => Token::Div, + "min" => Token::Min, + "max" => Token::Max, + "mod" => Token::Mod, + "divmod" => Token::DivMod, + "exp" => Token::Exp, + "and" => Token::And, + "band" => Token::BAnd, + "or" => Token::Or, + "bor" => Token::BOr, + "xor" => Token::Xor, + "bxor" => Token::BXor, + "shl" => Token::Shl, + "shr" => Token::Shr, + "rotl" => Token::Rotl, + "rotr" => Token::Rotr, + "eq" => Token::Eq, + "neq" => Token::Neq, + "gt" => Token::Gt, + "gte" => Token::Gte, + "lt" => Token::Lt, + "lte" => Token::Lte, + "store" => Token::Store, + "add_imm" => Token::AddImm, + "sub_imm" => Token::SubImm, + "mul_imm" => Token::MulImm, + "div_imm" => Token::DivImm, + "min_imm" => Token::MinImm, + "max_imm" => Token::MaxImm, + "mod_imm" => Token::ModImm, + "divmod_imm" => Token::DivModImm, + "exp_imm" => Token::ExpImm, + "and_imm" => Token::AndImm, + "band_imm" => Token::BAndImm, + "or_imm" => Token::OrImm, + "bor_imm" => Token::BOrImm, + "xor_imm" => Token::XorImm, + "bxor_imm" => Token::BXorImm, + "shl_imm" => Token::ShlImm, + "shr_imm" => Token::ShrImm, + "rotl_imm" => Token::RotlImm, + "rotr_imm" => Token::RotrImm, + "inv" => Token::Inv, + "incr" => Token::Incr, + "pow2" => Token::Pow2, + "not" => Token::Not, + "bnot" => Token::BNot, + "popcnt" => Token::PopCnt, + "is_odd" => Token::IsOdd, + "cast" => Token::Cast, + "ptrtoint" => Token::PtrToInt, + "inttoprt" => Token::IntToPtr, + "truncw" => Token::TruncW, + "neg" => Token::Neg, + "const" => Token::Const, + "select" => Token::Select, + "assert" => Token::Assert, + "assertz" => Token::Assertz, + "alloca" => Token::Alloca, + "unreachable" => Token::Unreachable, + "unchecked" => Token::Unchecked, + "checked" => Token::Checked, + "wrapping" => Token::Wrapping, + "overflowing" => Token::Overflowing, + "i1" => Token::I1, + "i8" => Token::I8, + "u8" => Token::U8, + "i16" => Token::I16, + "u16" => Token::U16, + "i32" => Token::I32, + "u32" => Token::U32, + "i64" => Token::I64, + "u64" => Token::U64, + "i128" => Token::I128, + "u128" => Token::U128, + "u256" => Token::U256, + "isize" => Token::ISize, + "usize" => Token::USize, + "f64" => Token::F64, + "felt" => Token::Felt, + "mut" => Token::Mut, + "as" => Token::As, + "global" => Token::Global, + "symbol" => Token::Symbol, + "iadd" => Token::IAdd, + "\"" => Token::DoubleQuote, + "=" => Token::Equal, + "=>" => Token::RDoubleArrow, + "+" => Token::Plus, + "-" => Token::Minus, + "->" => Token::RArrow, + "*" => Token::Star, + "&" => Token::Ampersand, + "!" => Token::Bang, + ":" => Token::Colon, + "::" => Token::ColonColon, + ";" => Token::Semicolon, + "," => Token::Comma, + "[" => Token::LBracket, + "]" => Token::RBracket, + "(" => Token::LParen, + ")" => Token::RParen, + "{" => Token::LBrace, + "}" => Token::RBrace, + "." => Token::Dot, + "@" => Token::At, + } +} diff --git a/hir-parser/src/parser/mod.rs b/hir-parser/src/parser/mod.rs new file mode 100644 index 000000000..2b0a30097 --- /dev/null +++ b/hir-parser/src/parser/mod.rs @@ -0,0 +1,257 @@ +// Simple macro used in the grammar definition for constructing spans +macro_rules! span { + ($l:expr, $r:expr) => { + miden_diagnostics::SourceSpan::new($l, $r) + }; + ($i:expr) => { + miden_diagnostics::SourceSpan::new($i, $i) + }; +} + +lalrpop_mod!( + #[allow(clippy::all)] + grammar, + "/parser/grammar.rs" +); + +use std::sync::Arc; + +use miden_diagnostics::{ + CodeMap, Diagnostic, DiagnosticsHandler, Label, SourceIndex, SourceSpan, ToDiagnostic, +}; +use miden_parsing::{Scanner, Source}; + +use crate::{ + ast, + lexer::{Lexed, Lexer, LexicalError, Token}, +}; + +pub type Parser = miden_parsing::Parser<()>; + +#[derive(Debug, thiserror::Error)] +pub enum ParseError { + #[error(transparent)] + Lexer(#[from] LexicalError), + #[error("error reading {path:?}: {source}")] + FileError { + source: std::io::Error, + path: std::path::PathBuf, + }, + #[error("invalid token")] + InvalidToken(SourceIndex), + #[error("unexpected end of file")] + UnexpectedEof { + at: SourceIndex, + expected: Vec, + }, + #[error("unrecognized token '{token}'")] + UnrecognizedToken { + span: SourceSpan, + token: Token, + expected: Vec, + }, + #[error("extraneous token '{token}'")] + ExtraToken { span: SourceSpan, token: Token }, + #[error("parsing failed, see diagnostics for details")] + Failed, +} +impl Eq for ParseError {} +impl PartialEq for ParseError { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Lexer(l), Self::Lexer(r)) => l == r, + (Self::FileError { .. }, Self::FileError { .. }) => true, + (Self::InvalidToken(_), Self::InvalidToken(_)) => true, + ( + Self::UnexpectedEof { + expected: ref l, .. + }, + Self::UnexpectedEof { + expected: ref r, .. + }, + ) => l == r, + ( + Self::UnrecognizedToken { + token: lt, + expected: ref l, + .. + }, + Self::UnrecognizedToken { + token: rt, + expected: ref r, + .. + }, + ) => lt == rt && l == r, + (Self::ExtraToken { token: l, .. }, Self::ExtraToken { token: r, .. }) => l == r, + (Self::Failed, Self::Failed) => true, + _ => false, + } + } +} +impl From> for ParseError { + fn from(err: lalrpop_util::ParseError) -> Self { + use lalrpop_util::ParseError as LError; + + match err { + LError::InvalidToken { location } => Self::InvalidToken(location), + LError::UnrecognizedEof { + location: at, + expected, + } => Self::UnexpectedEof { at, expected }, + LError::UnrecognizedToken { + token: (l, token, r), + expected, + } => Self::UnrecognizedToken { + span: SourceSpan::new(l, r), + token, + expected, + }, + LError::ExtraToken { + token: (l, token, r), + } => Self::ExtraToken { + span: SourceSpan::new(l, r), + token, + }, + LError::User { error } => error, + } + } +} +impl ToDiagnostic for ParseError { + fn to_diagnostic(self) -> Diagnostic { + match self { + Self::Lexer(err) => err.to_diagnostic(), + Self::InvalidToken(start) => Diagnostic::error() + .with_message("invalid token") + .with_labels(vec![Label::primary( + start.source_id(), + SourceSpan::new(start, start), + )]), + Self::UnexpectedEof { at, ref expected } => { + let mut message = "expected one of: ".to_string(); + for (i, t) in expected.iter().enumerate() { + if i == 0 { + message.push_str(&format!("'{}'", t)); + } else { + message.push_str(&format!(", '{}'", t)); + } + } + + Diagnostic::error() + .with_message("unexpected eof") + .with_labels(vec![Label::primary( + at.source_id(), + SourceSpan::new(at, at), + ) + .with_message(message)]) + } + Self::UnrecognizedToken { + span, ref expected, .. + } => { + let mut message = "expected one of: ".to_string(); + for (i, t) in expected.iter().enumerate() { + if i == 0 { + message.push_str(&format!("'{}'", t)); + } else { + message.push_str(&format!(", '{}'", t)); + } + } + + Diagnostic::error() + .with_message("unexpected token") + .with_labels(vec![ + Label::primary(span.source_id(), span).with_message(message) + ]) + } + Self::ExtraToken { span, .. } => Diagnostic::error() + .with_message("extraneous token") + .with_labels(vec![Label::primary(span.source_id(), span)]), + err => Diagnostic::error().with_message(err.to_string()), + } + } +} + +impl miden_parsing::Parse for ast::Program { + type Parser = grammar::ProgramParser; + type Error = ParseError; + type Config = (); + type Token = Lexed; + + fn root_file_error(source: std::io::Error, path: std::path::PathBuf) -> Self::Error { + ParseError::FileError { source, path } + } + + fn parse( + parser: &Parser, + diagnostics: &DiagnosticsHandler, + source: S, + ) -> Result + where + S: Source, + { + let scanner = Scanner::new(source); + let lexer = Lexer::new(scanner); + Self::parse_tokens(diagnostics, parser.codemap.clone(), lexer) + } + + fn parse_tokens>( + diagnostics: &DiagnosticsHandler, + codemap: Arc, + tokens: S, + ) -> Result { + let mut next_var = 0; + let result = Self::Parser::new().parse(diagnostics, &codemap, &mut next_var, tokens); + match result { + Ok(ast) => { + if diagnostics.has_errors() { + return Err(ParseError::Failed); + } + Ok(ast) + } + Err(lalrpop_util::ParseError::User { error }) => Err(error), + Err(err) => Err(err.into()), + } + } +} + +impl miden_parsing::Parse for ast::Module { + type Parser = grammar::ModuleParser; + type Error = ParseError; + type Config = (); + type Token = Lexed; + + fn root_file_error(source: std::io::Error, path: std::path::PathBuf) -> Self::Error { + ParseError::FileError { source, path } + } + + fn parse( + parser: &Parser, + diagnostics: &DiagnosticsHandler, + source: S, + ) -> Result + where + S: Source, + { + let scanner = Scanner::new(source); + let lexer = Lexer::new(scanner); + Self::parse_tokens(diagnostics, parser.codemap.clone(), lexer) + } + + fn parse_tokens>( + diagnostics: &DiagnosticsHandler, + codemap: Arc, + tokens: S, + ) -> Result { + let mut next_var = 0; + let result = Self::Parser::new().parse(diagnostics, &codemap, &mut next_var, tokens); + match result { + Ok(ast) => { + if diagnostics.has_errors() { + return Err(ParseError::Failed); + } + Ok(ast) + } + Err(lalrpop_util::ParseError::User { error }) => Err(error), + Err(err) => Err(err.into()), + } + } +} diff --git a/hir-parser/src/symbols.rs b/hir-parser/src/symbols.rs new file mode 100644 index 000000000..edccfe518 --- /dev/null +++ b/hir-parser/src/symbols.rs @@ -0,0 +1,163 @@ +use core::fmt; +use core::mem; +use core::ops::Deref; +use core::str; + +use std::collections::BTreeMap; +use std::sync::RwLock; + +lazy_static::lazy_static! { + static ref SYMBOL_TABLE: SymbolTable = SymbolTable::new(); +} + +struct SymbolTable { + interner: RwLock, +} +impl SymbolTable { + pub fn new() -> Self { + Self { + interner: RwLock::new(Interner::new()), + } + } +} +unsafe impl Sync for SymbolTable {} + +/// A symbol is an interned string. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub struct Symbol(SymbolIndex); + +impl Symbol { + #[inline] + pub const fn new(n: u32) -> Self { + Self(SymbolIndex::new(n)) + } + + /// Maps a string to its interned representation. + pub fn intern>(string: S) -> Self { + let string = string.into(); + with_interner(|interner| interner.intern(string)) + } + + pub fn as_str(self) -> &'static str { + with_read_only_interner(|interner| unsafe { + // This is safe because the interned string will live for the + // lifetime of the program + mem::transmute::<&str, &'static str>(interner.get(self)) + }) + } + + #[inline] + pub fn as_u32(self) -> u32 { + self.0.as_u32() + } + + #[inline] + pub fn as_usize(self) -> usize { + self.0.as_usize() + } +} +impl fmt::Debug for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}({:?})", self, self.0) + } +} +impl fmt::Display for Symbol { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.as_str(), f) + } +} +impl PartialOrd for Symbol { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for Symbol { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.as_str().cmp(other.as_str()) + } +} +impl> PartialEq for Symbol { + fn eq(&self, other: &T) -> bool { + self.as_str() == other.deref() + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct SymbolIndex(u32); +impl SymbolIndex { + // shave off 256 indices at the end to allow space for packing these indices into enums + pub const MAX_AS_U32: u32 = 0xFFFF_FF00; + + #[inline] + const fn new(n: u32) -> Self { + assert!(n <= Self::MAX_AS_U32, "out of range value used"); + + SymbolIndex(n) + } + + #[inline] + pub fn as_u32(self) -> u32 { + self.0 + } + + #[inline] + pub fn as_usize(self) -> usize { + self.0 as usize + } +} +impl From for u32 { + #[inline] + fn from(v: SymbolIndex) -> u32 { + v.as_u32() + } +} +impl From for usize { + #[inline] + fn from(v: SymbolIndex) -> usize { + v.as_usize() + } +} + +#[derive(Default)] +struct Interner { + pub names: BTreeMap<&'static str, Symbol>, + pub strings: Vec<&'static str>, +} + +impl Interner { + pub fn new() -> Self { + let this = Interner::default(); + this + } + + pub fn intern(&mut self, string: String) -> Symbol { + if let Some(&name) = self.names.get(string.as_str()) { + return name; + } + + let name = Symbol::new(self.strings.len() as u32); + + let string = string.into_boxed_str(); + let string: &'static str = Box::leak(string); + self.strings.push(string); + self.names.insert(string, name); + name + } + + pub fn get(&self, symbol: Symbol) -> &str { + self.strings[symbol.0.as_usize()] + } +} + +// If an interner exists, return it. Otherwise, prepare a fresh one. +#[inline] +fn with_interner T>(f: F) -> T { + let mut r = SYMBOL_TABLE.interner.write().unwrap(); + f(&mut r) +} + +#[inline] +fn with_read_only_interner T>(f: F) -> T { + let r = SYMBOL_TABLE.interner.read().unwrap(); + f(&r) +} diff --git a/hir-transform/src/inline_blocks.rs b/hir-transform/src/inline_blocks.rs index f77287bdc..1d7c55d07 100644 --- a/hir-transform/src/inline_blocks.rs +++ b/hir-transform/src/inline_blocks.rs @@ -278,31 +278,42 @@ mod tests { /// ```text,ignore /// pub fn test(*mut u8, i32) -> *mut u8 { /// entry(ptr0: *mut u8, offset: i32): + /// { /// zero = const.u32 0 /// ptr1 = ptrtoint ptr0 : u32 /// is_null = eq ptr1, zero /// br blk0(ptr1, is_null) + /// } /// /// blk0(ptr2: u32, is_null1: i1): + /// { /// condbr is_null1, blk2(ptr0), blk1(ptr2) + /// } /// /// blk1(ptr3: u32): + /// { /// ptr4 = add ptr3, offset /// is_null2 = eq ptr4, zero /// condbr is_null2, blk4(ptr0), blk5(ptr4) /// /// blk2(result0: *mut u8) /// br blk3 + /// } /// /// blk3: - /// ret result0 + /// { + /// ret (result0) + /// } /// - /// blk4(result1: *mut u8) - /// ret result1 + /// blk4(result1: *mut u8): + /// ret (result1) + /// } /// /// blk5(ptr5: u32): + /// { /// ptr6 = inttoptr ptr5 : *mut u8 - /// ret ptr6 + /// ret (ptr6) + /// } /// } /// ``` /// @@ -311,25 +322,35 @@ mod tests { /// ```text,ignore /// pub fn test(*mut u8, i32) -> *mut u8 { /// entry(ptr0: *mut u8, offset: i32): + /// { /// zero = const.u32 0 /// ptr1 = ptrtoint ptr0 : u32 /// is_null = eq ptr1, zero /// condbr is_null, blk2, blk1 + /// } /// /// blk1: + /// { /// ptr2 = add ptr1, offset /// is_null1 = eq ptr2, zero /// condbr is_null1, blk3, blk4 + /// } /// /// blk2: - /// ret ptr0 + /// { + /// ret (ptr0) + /// } /// /// blk3: - /// ret ptr0 + /// { + /// ret (ptr0) + /// } /// /// blk4: + /// { /// ptr3 = inttoptr ptr2 : *mut u8 - /// ret ptr3 + /// ret (ptr3) + /// } /// ``` /// /// In short, regardless of block arguments, control flow edges between blocks @@ -429,26 +450,36 @@ mod tests { let expected = "pub fn inlining_test(*mut u8, i32) -> *mut u8 { block0(v0: *mut u8, v1: i32): +{ v8 = ptrtoint v0 : u32 v9 = eq v8, 0 : i1 condbr v9, block3(v0), block2(v8) +} block2(v4: u32): +{ v10 = cast v4 : i32 v11 = add v10, v1 : i32 v12 = cast v11 : u32 v13 = eq v12, 0 : i1 condbr v13, block5(v0), block6(v12) +} block3(v5: *mut u8): - ret v5 +{ + ret (v5) +} block5(v6: *mut u8): - ret v6 +{ + ret (v6) +} block6(v7: u32): +{ v14 = inttoptr v7 : *mut u8 - ret v14 + ret (v14) +} } "; diff --git a/hir-transform/src/split_critical_edges.rs b/hir-transform/src/split_critical_edges.rs index 1d09a73c8..b73e309b2 100644 --- a/hir-transform/src/split_critical_edges.rs +++ b/hir-transform/src/split_critical_edges.rs @@ -152,21 +152,29 @@ mod tests { /// ```text,ignore /// pub fn test(*mut u8, u32) -> *mut u8 { /// entry(ptr0: *mut u8, n0: u32): + /// { /// ptr1 = ptrtoint ptr0 : u32 /// br blk0(ptr1, n0) + /// } /// /// blk0(ptr2: u32, n1: u32): + /// { /// is_null = eq ptr2, 0 /// condbr is_null, blk2(ptr0), blk1(ptr2, n1) + /// } /// /// blk1(ptr3: u32, n2: u32): + /// { /// ptr4 = sub ptr3, n2 /// n3 = sub n2, 1 /// is_zero = eq n3, 0 /// condbr is_zero, blk2(ptr4), blk0(ptr4, n3) + /// } /// /// blk2(result0: *mut u8) - /// ret result0 + /// { + /// ret (result0) + /// } /// } /// ``` /// @@ -248,31 +256,45 @@ mod tests { let expected = "pub fn sce(*mut u8, u32) -> *mut u8 { block0(v0: *mut u8, v1: u32): +{ v7 = ptrtoint v0 : u32 br block1(v7, v1) +} block1(v2: u32, v3: u32): +{ v8 = eq v2, 0 : i1 condbr v8, block4, block2(v2, v3) +} block4: +{ br block3(v0) +} block2(v4: u32, v5: u32): +{ v9 = sub v4, v5 : u32 v10 = sub v5, 1 : u32 v11 = eq v10, 0 : i1 condbr v11, block6, block5 +} block6: +{ br block3(v9) +} block5: +{ br block1(v9, v10) +} block3(v6: u32): +{ v12 = inttoptr v6 : *mut u8 - ret v12 + ret (v12) +} } "; diff --git a/hir-transform/src/treeify.rs b/hir-transform/src/treeify.rs index aca8d1dcc..961ddcee9 100644 --- a/hir-transform/src/treeify.rs +++ b/hir-transform/src/treeify.rs @@ -702,33 +702,46 @@ mod tests { let expected = "pub fn sum_matrix(*mut u32, u32, u32) -> u32 { block0(v0: *mut u32, v1: u32, v2: u32): +{ v10 = const.u32 0 : u32 v11 = ptrtoint v0 : u32 v12 = neq v11, 0 : i1 condbr v12, block2, block7 +} block7: - ret v10 +{ + ret (v10) +} block2: +{ v13 = const.u32 0 : u32 v14 = const.u32 0 : u32 v15 = mul v2, 4 : u32 br block3(v10, v13, v14) +} block3(v4: u32, v5: u32, v6: u32): +{ v16 = lt v5, v1 : i1 v17 = mul v5, v15 : u32 condbr v16, block4(v4, v5, v6), block8 +} block8: - ret v4 +{ + ret (v4) +} block4(v7: u32, v8: u32, v9: u32): +{ v18 = lt v9, v2 : i1 condbr v18, block5, block6 +} block5: +{ v19 = mul v9, 4 : u32 v20 = add v17, v19 : u32 v21 = add v11, v20 : u32 @@ -737,12 +750,15 @@ block5: v24 = add v7, v23 : u32 v25 = incr v9 : u32 br block4(v24, v8, v25) +} block6: +{ v26 = incr v8 : u32 v27 = const.u32 0 : u32 br block3(v7, v26, v27) } +} "; let transformed = function.to_string(); diff --git a/hir/src/write.rs b/hir/src/write.rs index 30b59464f..65504d7dc 100644 --- a/hir/src/write.rs +++ b/hir/src/write.rs @@ -11,9 +11,11 @@ pub fn write_function(w: &mut dyn Write, func: &Function) -> fmt::Result { } write_block_header(w, func, block, 4)?; + writeln!(w, "{{")?; for inst in block_data.insts() { write_instruction(w, func, inst, 4)?; } + writeln!(w, "}}")?; } writeln!(w, "}}") } @@ -170,7 +172,14 @@ fn write_operands( Instruction::BinaryOpImm(BinaryOpImm { arg, imm, .. }) => write!(w, " {}, {}", arg, imm), Instruction::UnaryOp(UnaryOp { arg, .. }) => write!(w, " {}", arg), Instruction::UnaryOpImm(UnaryOpImm { imm, .. }) => write!(w, " {}", imm), - Instruction::Ret(Ret { args, .. }) => write!(w, " {}", DisplayValues(args.as_slice(pool))), + Instruction::Ret(Ret { args, .. }) => { + if args.len(pool) > 0 { + write!(w, " ({})", DisplayValues(args.as_slice(pool))) + } + else { + Ok(()) + } + }, Instruction::RetImm(RetImm { arg, .. }) => write!(w, " {arg}"), Instruction::Call(Call { callee, args, .. }) => { write!(w, " {}({})", callee, DisplayValues(args.as_slice(pool))) @@ -188,21 +197,13 @@ fn write_operands( write_block_args(w, else_dest.1.as_slice(pool)) } Instruction::Br(Br { - op, destination, args, .. - }) if *op == Opcode::Br => { + }) => { write!(w, " {}", destination)?; write_block_args(w, args.as_slice(pool)) } - Instruction::Br(Br { - destination, args, .. - }) => { - let args = args.as_slice(pool); - write!(w, " {}, {}", args[0], destination)?; - write_block_args(w, &args[1..]) - } Instruction::Switch(Switch { arg, arms, default, .. }) => { From 4d973cf4382085be7a19473e075f6349585cfb53 Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Fri, 20 Oct 2023 18:56:06 +0200 Subject: [PATCH 02/12] Move hir-parser to hir/src/parser --- Cargo.lock | 26 +------------ Cargo.toml | 1 - hir-parser/Cargo.toml | 26 ------------- hir-parser/README.md | 39 ------------------- hir/Cargo.toml | 4 ++ {hir-parser => hir}/build.rs | 0 .../src => hir/src/parser}/ast/block.rs | 0 .../src => hir/src/parser}/ast/functions.rs | 0 .../src => hir/src/parser}/ast/globals.rs | 0 .../src => hir/src/parser}/ast/instruction.rs | 0 {hir-parser/src => hir/src/parser}/ast/mod.rs | 0 .../src => hir/src/parser}/ast/types.rs | 0 .../src => hir/src/parser}/lexer/mod.rs | 0 {hir-parser/src => hir/src/parser}/lib.rs | 0 .../src/parser}/parser/grammar.lalrpop | 0 .../src => hir/src/parser}/parser/mod.rs | 0 {hir-parser/src => hir/src/parser}/symbols.rs | 0 17 files changed, 6 insertions(+), 90 deletions(-) delete mode 100644 hir-parser/Cargo.toml delete mode 100644 hir-parser/README.md rename {hir-parser => hir}/build.rs (100%) rename {hir-parser/src => hir/src/parser}/ast/block.rs (100%) rename {hir-parser/src => hir/src/parser}/ast/functions.rs (100%) rename {hir-parser/src => hir/src/parser}/ast/globals.rs (100%) rename {hir-parser/src => hir/src/parser}/ast/instruction.rs (100%) rename {hir-parser/src => hir/src/parser}/ast/mod.rs (100%) rename {hir-parser/src => hir/src/parser}/ast/types.rs (100%) rename {hir-parser/src => hir/src/parser}/lexer/mod.rs (100%) rename {hir-parser/src => hir/src/parser}/lib.rs (100%) rename {hir-parser/src => hir/src/parser}/parser/grammar.lalrpop (100%) rename {hir-parser/src => hir/src/parser}/parser/mod.rs (100%) rename {hir-parser/src => hir/src/parser}/symbols.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e6ceb25cc..787162f67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -897,6 +897,8 @@ dependencies = [ "anyhow", "cranelift-entity", "intrusive-collections", + "lalrpop", + "lalrpop-util", "miden-assembly", "miden-diagnostics", "miden-hir-symbol", @@ -961,30 +963,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "miden-ir-parser" -version = "0.4.0" -dependencies = [ - "lalrpop", - "lalrpop-util", - "lazy_static", - "miden-diagnostics", - "miden-parsing", - "pretty_assertions", - "regex", - "thiserror", -] - -[[package]] -name = "miden-parsing" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d36dfec2c0319b3773a83627318f92a0212077bed80148c86e8b09af60cd1a88" -dependencies = [ - "miden-diagnostics", - "thiserror", -] - [[package]] name = "midenc" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index e286c4997..b0811b035 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ resolver = "2" members = [ "codegen/*", "hir", - "hir-parser", "hir-analysis", "hir-pass", "hir-symbol", diff --git a/hir-parser/Cargo.toml b/hir-parser/Cargo.toml deleted file mode 100644 index 65e5e6e06..000000000 --- a/hir-parser/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "miden-ir-parser" -version = "0.4.0" -description = "Parser for the Miden IR language" -authors = ["miden contributors"] -readme = "README.md" -license = "MIT" -repository = "https://github.com/0xPolygonMiden/miden-ir" -categories = ["Compilers"] -keywords = ["compiler", "miden"] -edition = "2021" -rust-version = "1.67" - -[build-dependencies] -lalrpop = { version = "0.20", default-features = false } - -[dependencies] -miden-diagnostics = "0.1" -miden-parsing = "0.1" -lalrpop-util="0.20" -lazy_static = "1.4" -regex = "1" -thiserror = "1.0" - -[dev-dependencies] -pretty_assertions = "1.0" diff --git a/hir-parser/README.md b/hir-parser/README.md deleted file mode 100644 index a6d7558cc..000000000 --- a/hir-parser/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Parser - -This crate contains the parser for Miden IR. - -The purpose of the parser is to parse the Miden IR language into an Abstract Syntax Tree. - -## Generating the Abstract Syntax Tree (AST) - -The parser uses [Logos](https://github.com/maciejhirsz/logos/) to generate a custom lexer, which is then fed into the parser generated by [LALRPOP](https://github.com/lalrpop/lalrpop/). - -To create an AST from a given Miden IR program or module, pass your source to the public `parse` function, which will return the AST or an `Error` of type `ScanError` or `ParseError`. - -The `parse` function will first tokenize the source using the lexer, then map the resulting tokens to new tokens accepted by the parser, which are of type `(usize, Token, usize)`. Each invalid token will be stored as `ScanError`. Finally, if no `ScanError` occurred, `parse` feeds the tokens to the parser to generate a Result with the corresponding AST (or `ParseError`). - -Example usage: - -```Rust -// parse the source string to a Result containing the AST or an Error -let ast = parse(source.as_str()); -``` - -## AST - -The Miden IR AST (`Source`) contains a vector of `SourceSection`, each of which contains the result of parsing a section in a Miden IR program or module. - - - -TODO: - -The `SourceSection` types are: - -- `AirDef`, which holds the name of the AIR. -- `Constant`, which holds a named constant to be used to write constraints. -- `Trace`, which contains the parsed trace column information for the main and auxiliary execution traces. Each column or group of columns is represented by its identifier and can be accessed in constraints using this identifier. These columns can also be accessed using the built-in variables `$main[idx]` and `$aux[idx]`, where `idx` is the index of the column in the trace. -- `PublicInputs`, which is a vector of all of the public inputs defined in the module. Each public input is represented by its identifier and a fixed size. -- `PeriodicColumns`, which is a vector of all of the periodic columns defined in the module. Each periodic column is represented by its identifier and a vector containing the pattern of its repeated (periodic) values. -- `RandomValues`, which is a vector of all of the random values provided by the verifier. Each random value or group of random values is represented by its identifier and can be accessed in constraints using this identifier. These random values can also be accessed using `$rand[idx]`, where `rand` is the name of the random values array and `idx` is the index of the random value in that array. -- `BoundaryConstraints`, which contains a vector of `BoundaryStmt` statements, each of which can be either a boundary constraint or an intermediate variable. Each boundary constraint is represented as an expression tree. Variables can be scalars, vectors or matrices containing expression trees. -- `IntegrityConstraints`, which contains a vector of `IntegrityStmt` statements, each of which can be either an integrity constraint or an intermediate variable. Each integrity constraint is represented as an expression tree. Variables can be scalars, vectors or matrices containing expression trees. \ No newline at end of file diff --git a/hir/Cargo.toml b/hir/Cargo.toml index e9f0de04e..010dc883a 100644 --- a/hir/Cargo.toml +++ b/hir/Cargo.toml @@ -10,10 +10,14 @@ license.workspace = true readme.workspace = true edition.workspace = true +[build-dependencies] +lalrpop = { version = "0.20", default-features = false } + [dependencies] anyhow.workspace = true cranelift-entity.workspace = true intrusive-collections.workspace = true +lalrpop-util="0.20" miden-assembly.workspace = true miden-diagnostics.workspace = true miden-hir-symbol.workspace = true diff --git a/hir-parser/build.rs b/hir/build.rs similarity index 100% rename from hir-parser/build.rs rename to hir/build.rs diff --git a/hir-parser/src/ast/block.rs b/hir/src/parser/ast/block.rs similarity index 100% rename from hir-parser/src/ast/block.rs rename to hir/src/parser/ast/block.rs diff --git a/hir-parser/src/ast/functions.rs b/hir/src/parser/ast/functions.rs similarity index 100% rename from hir-parser/src/ast/functions.rs rename to hir/src/parser/ast/functions.rs diff --git a/hir-parser/src/ast/globals.rs b/hir/src/parser/ast/globals.rs similarity index 100% rename from hir-parser/src/ast/globals.rs rename to hir/src/parser/ast/globals.rs diff --git a/hir-parser/src/ast/instruction.rs b/hir/src/parser/ast/instruction.rs similarity index 100% rename from hir-parser/src/ast/instruction.rs rename to hir/src/parser/ast/instruction.rs diff --git a/hir-parser/src/ast/mod.rs b/hir/src/parser/ast/mod.rs similarity index 100% rename from hir-parser/src/ast/mod.rs rename to hir/src/parser/ast/mod.rs diff --git a/hir-parser/src/ast/types.rs b/hir/src/parser/ast/types.rs similarity index 100% rename from hir-parser/src/ast/types.rs rename to hir/src/parser/ast/types.rs diff --git a/hir-parser/src/lexer/mod.rs b/hir/src/parser/lexer/mod.rs similarity index 100% rename from hir-parser/src/lexer/mod.rs rename to hir/src/parser/lexer/mod.rs diff --git a/hir-parser/src/lib.rs b/hir/src/parser/lib.rs similarity index 100% rename from hir-parser/src/lib.rs rename to hir/src/parser/lib.rs diff --git a/hir-parser/src/parser/grammar.lalrpop b/hir/src/parser/parser/grammar.lalrpop similarity index 100% rename from hir-parser/src/parser/grammar.lalrpop rename to hir/src/parser/parser/grammar.lalrpop diff --git a/hir-parser/src/parser/mod.rs b/hir/src/parser/parser/mod.rs similarity index 100% rename from hir-parser/src/parser/mod.rs rename to hir/src/parser/parser/mod.rs diff --git a/hir-parser/src/symbols.rs b/hir/src/parser/symbols.rs similarity index 100% rename from hir-parser/src/symbols.rs rename to hir/src/parser/symbols.rs From 6a9c9892c3ee8400b97d8ba2f6aeb535f6705e27 Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Fri, 20 Oct 2023 19:00:42 +0200 Subject: [PATCH 03/12] Remove symbols.rs and types.rs --- hir/src/parser/ast/types.rs | 90 -------------------- hir/src/parser/symbols.rs | 163 ------------------------------------ 2 files changed, 253 deletions(-) delete mode 100644 hir/src/parser/ast/types.rs delete mode 100644 hir/src/parser/symbols.rs diff --git a/hir/src/parser/ast/types.rs b/hir/src/parser/ast/types.rs deleted file mode 100644 index 1c6d6d02c..000000000 --- a/hir/src/parser/ast/types.rs +++ /dev/null @@ -1,90 +0,0 @@ -use super::*; - -/// The types of values which can be represented in an AirScript program -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum Type { - /// The singleton type - Unit, - /// The empty type - Never, - /// The type of a single bit, i.e., the boolean type - I1, - /// Signed 8-bit integers - I8, - /// Unsigned 8-bit integers - U8, - /// Signed 16-bit integers - I16, - /// Unsigned 16-bit integers - U16, - /// Signed 32-bit integers - I32, - /// Unsigned 32-bit integers - U32, - /// Signed 64-bit integers - I64, - /// Unsigned 64-bit integers - U64, - /// Signed 128-bit integers - I128, - /// Unsigned 128-bit integers - U128, - /// Unsigned 256-bit integers - U256, - /// Signed integers of size equal to the native architecture word size - ISize, - /// Unsigned integers of size equal to the native architecture word size - USize, - /// 64-bit floats - F64, - /// Field elements - Felt, - /// Pointers to values of the inner type - Ptr(Box), - /// Native pointers to values of the inner type - NativePtr(Box), - /// Structs containing field values of the specified types in the specified order. - /// The empty struct is a legal type. - Struct(Vec), - /// Arrays of the specified length, containing values of the specified type. - Array(Box, u128), -} -impl fmt::Display for Type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Unit => f.write_str("()"), - Self::Never => f.write_str("!"), - Self::I1 => f.write_str("i1"), - Self::I8 => f.write_str("i8"), - Self::U8 => f.write_str("u8"), - Self::I16 => f.write_str("i16"), - Self::U16 => f.write_str("u16"), - Self::I32 => f.write_str("i32"), - Self::U32 => f.write_str("u32"), - Self::I64 => f.write_str("i64"), - Self::U64 => f.write_str("u64"), - Self::I128 => f.write_str("i128"), - Self::U128 => f.write_str("u128"), - Self::U256 => f.write_str("u256"), - Self::ISize => f.write_str("isize"), - Self::USize => f.write_str("usize"), - Self::F64 => f.write_str("f64"), - Self::Felt => f.write_str("felt"), - Self::Ptr(inner) => write!(f, "*mut {}", inner), - Self::NativePtr(inner) => write!(f, "&mut {}", inner), - Self::Struct(types) => { - f.write_str("{ ")?; - for (i, t) in types.iter().enumerate() { - if i != 0 { - write!(f, ", {}", t)?; - } else { - write!(f, "{}", t)?; - } - f.write_str(" }")?; - } - Ok(()) - } - Self::Array(inner, length) => write!(f, "[ {} ; {} ]", inner, length), - } - } -} diff --git a/hir/src/parser/symbols.rs b/hir/src/parser/symbols.rs deleted file mode 100644 index edccfe518..000000000 --- a/hir/src/parser/symbols.rs +++ /dev/null @@ -1,163 +0,0 @@ -use core::fmt; -use core::mem; -use core::ops::Deref; -use core::str; - -use std::collections::BTreeMap; -use std::sync::RwLock; - -lazy_static::lazy_static! { - static ref SYMBOL_TABLE: SymbolTable = SymbolTable::new(); -} - -struct SymbolTable { - interner: RwLock, -} -impl SymbolTable { - pub fn new() -> Self { - Self { - interner: RwLock::new(Interner::new()), - } - } -} -unsafe impl Sync for SymbolTable {} - -/// A symbol is an interned string. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub struct Symbol(SymbolIndex); - -impl Symbol { - #[inline] - pub const fn new(n: u32) -> Self { - Self(SymbolIndex::new(n)) - } - - /// Maps a string to its interned representation. - pub fn intern>(string: S) -> Self { - let string = string.into(); - with_interner(|interner| interner.intern(string)) - } - - pub fn as_str(self) -> &'static str { - with_read_only_interner(|interner| unsafe { - // This is safe because the interned string will live for the - // lifetime of the program - mem::transmute::<&str, &'static str>(interner.get(self)) - }) - } - - #[inline] - pub fn as_u32(self) -> u32 { - self.0.as_u32() - } - - #[inline] - pub fn as_usize(self) -> usize { - self.0.as_usize() - } -} -impl fmt::Debug for Symbol { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}({:?})", self, self.0) - } -} -impl fmt::Display for Symbol { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.as_str(), f) - } -} -impl PartialOrd for Symbol { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl Ord for Symbol { - fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.as_str().cmp(other.as_str()) - } -} -impl> PartialEq for Symbol { - fn eq(&self, other: &T) -> bool { - self.as_str() == other.deref() - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct SymbolIndex(u32); -impl SymbolIndex { - // shave off 256 indices at the end to allow space for packing these indices into enums - pub const MAX_AS_U32: u32 = 0xFFFF_FF00; - - #[inline] - const fn new(n: u32) -> Self { - assert!(n <= Self::MAX_AS_U32, "out of range value used"); - - SymbolIndex(n) - } - - #[inline] - pub fn as_u32(self) -> u32 { - self.0 - } - - #[inline] - pub fn as_usize(self) -> usize { - self.0 as usize - } -} -impl From for u32 { - #[inline] - fn from(v: SymbolIndex) -> u32 { - v.as_u32() - } -} -impl From for usize { - #[inline] - fn from(v: SymbolIndex) -> usize { - v.as_usize() - } -} - -#[derive(Default)] -struct Interner { - pub names: BTreeMap<&'static str, Symbol>, - pub strings: Vec<&'static str>, -} - -impl Interner { - pub fn new() -> Self { - let this = Interner::default(); - this - } - - pub fn intern(&mut self, string: String) -> Symbol { - if let Some(&name) = self.names.get(string.as_str()) { - return name; - } - - let name = Symbol::new(self.strings.len() as u32); - - let string = string.into_boxed_str(); - let string: &'static str = Box::leak(string); - self.strings.push(string); - self.names.insert(string, name); - name - } - - pub fn get(&self, symbol: Symbol) -> &str { - self.strings[symbol.0.as_usize()] - } -} - -// If an interner exists, return it. Otherwise, prepare a fresh one. -#[inline] -fn with_interner T>(f: F) -> T { - let mut r = SYMBOL_TABLE.interner.write().unwrap(); - f(&mut r) -} - -#[inline] -fn with_read_only_interner T>(f: F) -> T { - let r = SYMBOL_TABLE.interner.read().unwrap(); - f(&r) -} From fa3851d4803a11ee8aa34b81a0f6664806b3f0d8 Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Fri, 20 Oct 2023 19:31:46 +0200 Subject: [PATCH 04/12] Use hir definitions for CallConvention, ParameterExtension, ParameterPurpose, Identifier and FunctionIdentifier, remove Program, allow globals in module declarations --- hir/src/parser/ast/block.rs | 4 +- hir/src/parser/ast/functions.rs | 102 +++++--------------------- hir/src/parser/ast/globals.rs | 2 +- hir/src/parser/ast/instruction.rs | 10 +-- hir/src/parser/ast/mod.rs | 77 ++----------------- hir/src/parser/parser/grammar.lalrpop | 52 ++++++------- 6 files changed, 56 insertions(+), 191 deletions(-) diff --git a/hir/src/parser/ast/block.rs b/hir/src/parser/ast/block.rs index a7da7d592..dc0e85fb2 100644 --- a/hir/src/parser/ast/block.rs +++ b/hir/src/parser/ast/block.rs @@ -6,10 +6,10 @@ const INDENT: &str = " "; /// /// Labels must be unique within each function. pub struct Label { - pub name: Identifier, + pub name: Ident, } impl Label { - pub fn new(name: Identifier) -> Self { + pub fn new(name: Ident) -> Self { Self { name } } } diff --git a/hir/src/parser/ast/functions.rs b/hir/src/parser/ast/functions.rs index 44df73b97..313b18217 100644 --- a/hir/src/parser/ast/functions.rs +++ b/hir/src/parser/ast/functions.rs @@ -1,39 +1,5 @@ use super::*; -/// Represents an identifier that represents a function name. -/// -/// A function identifier is a non-empty sequence of identifiers, separated by double -/// colons ("::"). The last identifier in the sequence denotes the name of the function -/// itself. The other identifiers denote the module that the function can be found in. If -/// the function identifier only consists of a single identifier, then the function must -/// be found in the current module. -#[derive(Spanned)] -pub struct FunctionIdentifier { - #[span] - span: SourceSpan, - names: Vec, -} -impl FunctionIdentifier { - pub fn new(span: SourceSpan, names: Vec) -> Self { - Self { span, names } - } - - pub fn id(&self) -> &Identifier { - self.names.last().unwrap() - } -} -impl fmt::Display for FunctionIdentifier { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for (i, id) in self.names.iter().enumerate() { - if i > 0 { - f.write_str("::")?; - } - write!(f, "{}", id)?; - } - Ok(()) - } -} - /// The possible visibilities of a function pub enum Visibility { /// (Module) private visibility @@ -42,46 +8,18 @@ pub enum Visibility { Public, } -/// The possible calling convetions of a function -pub enum CallConvention { - /// Default call convention - Default, - /// Kernel call convention - Kernel, - /// Fast call convention - Fast, -} - -/// The possible purposes of a function parameter -pub enum ParameterPurpose { - /// Standard parameter - Standard, - /// Parameter for struct return - Sret, -} - -/// The possible extensions of a function parameter when filling up a word -pub enum ParameterExtension { - /// No extension - None, - /// 0 extended - Zero, - /// Sign extended - Signed, -} - /// A single parameter to a function. /// Parameter names are defined in the entry block for the function. pub struct FunctionParameter { /// The purpose of the parameter (default or struct return) - pub purpose: ParameterPurpose, + pub purpose: ArgumentPurpose, /// The bit extension for the parameter - pub extension: ParameterExtension, + pub extension: ArgumentExtension, /// The type of the parameter pub ty: Type, } impl FunctionParameter { - pub fn new(purpose: ParameterPurpose, extension: ParameterExtension, ty: Type) -> Self { + pub fn new(purpose: ArgumentPurpose, extension: ArgumentExtension, ty: Type) -> Self { Self { purpose, extension, @@ -92,13 +30,13 @@ impl FunctionParameter { impl fmt::Display for FunctionParameter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.purpose { - ParameterPurpose::Standard => Ok(()), - ParameterPurpose::Sret => f.write_str("sret "), + ArgumentPurpose::Default => Ok(()), + ArgumentPurpose::StructReturn => f.write_str("sret "), }?; match self.extension { - ParameterExtension::None => Ok(()), - ParameterExtension::Zero => f.write_str("zext "), - ParameterExtension::Signed => f.write_str("sext "), + ArgumentExtension::None => Ok(()), + ArgumentExtension::Zext => f.write_str("zext "), + ArgumentExtension::Sext => f.write_str("sext "), }?; write!(f, "{}", self.ty) } @@ -107,21 +45,21 @@ impl fmt::Display for FunctionParameter { /// A single return value from a function. pub struct FunctionReturn { /// The bit extension for the parameter - pub extension: ParameterExtension, + pub extension: ArgumentExtension, /// The type of the parameter pub ty: Type, } impl FunctionReturn { - pub fn new(extension: ParameterExtension, ty: Type) -> Self { + pub fn new(extension: ArgumentExtension, ty: Type) -> Self { Self { extension, ty } } } impl fmt::Display for FunctionReturn { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.extension { - ParameterExtension::None => Ok(()), - ParameterExtension::Zero => f.write_str("zext "), - ParameterExtension::Signed => f.write_str("sext "), + ArgumentExtension::None => Ok(()), + ArgumentExtension::Zext => f.write_str("zext "), + ArgumentExtension::Sext => f.write_str("sext "), }?; write!(f, "{}", self.ty) } @@ -133,8 +71,8 @@ pub struct FunctionSignature { #[span] pub span: SourceSpan, pub visibility: Visibility, - pub call_convention: CallConvention, - pub name: FunctionIdentifier, + pub call_convention: CallConv, + pub name: FunctionIdent, pub params: Vec, pub returns: Vec, } @@ -142,8 +80,8 @@ impl FunctionSignature { pub fn new( span: SourceSpan, visibility: Visibility, - call_convention: CallConvention, - name: FunctionIdentifier, + call_convention: CallConv, + name: FunctionIdent, params: Vec, returns: Vec, ) -> Self { @@ -164,9 +102,9 @@ impl fmt::Display for FunctionSignature { Visibility::Public => f.write_str("pub "), }?; match self.call_convention { - CallConvention::Default => Ok(()), - CallConvention::Kernel => f.write_str("kernel "), - CallConvention::Fast => f.write_str("fast "), + CallConv::SystemV => Ok(()), + CallConv::Kernel => f.write_str("kernel "), + CallConv::Fast => f.write_str("fast "), }?; write!(f, "{}(", self.name)?; for (i, param) in self.params.iter().enumerate() { diff --git a/hir/src/parser/ast/globals.rs b/hir/src/parser/ast/globals.rs index 465b6f23a..32b7d0708 100644 --- a/hir/src/parser/ast/globals.rs +++ b/hir/src/parser/ast/globals.rs @@ -5,7 +5,7 @@ use miden_diagnostics::{SourceSpan, Spanned}; use super::*; /// This is a type alias used to clarify that an identifier refers to a global variable -pub type GlobalVarId = Identifier; +pub type GlobalVarId = Ident; /// A constant value in the form of a hexadecimal string #[derive(Debug, Clone, PartialEq, Eq, Hash)] diff --git a/hir/src/parser/ast/instruction.rs b/hir/src/parser/ast/instruction.rs index 72a837058..8a62c95c4 100644 --- a/hir/src/parser/ast/instruction.rs +++ b/hir/src/parser/ast/instruction.rs @@ -5,10 +5,10 @@ use super::*; /// All intermediate values are named, and have an associated [Value]. /// Value identifiers must be globally unique. pub struct Value { - pub name: Identifier, + pub name: Ident, } impl Value { - pub fn new(name: Identifier) -> Self { + pub fn new(name: Ident) -> Self { Self { name } } } @@ -88,7 +88,7 @@ pub enum Operation { UnaryOp(UnaryOpCode, Value), UnaryImmOp(UnaryImmOpCode, Immediate), ReturnOp(Vec), - CallOp(CallOp, FunctionIdentifier, Vec), + CallOp(CallOp, FunctionIdent, Vec), CondOp(Value, Destination, Destination), BranchOp(Destination), SwitchOp(Value, Vec), @@ -485,7 +485,7 @@ impl fmt::Display for Offset { /// Used to distinguish between nested global value operations pub enum GlobalValueOpNested { - Symbol(Identifier, Offset), + Symbol(Ident, Offset), Load(Box, Offset), Cast(Box, Offset, Type), } @@ -513,7 +513,7 @@ impl fmt::Display for GlobalValueOpNested { /// Used to distinguish between top-level global value operations pub enum GlobalValueOp { - Symbol(Identifier, Offset), + Symbol(Ident, Offset), Load(GlobalValueOpNested, Offset), Cast(GlobalValueOpNested, Offset, Type), IAddImm(u128, Type, GlobalValueOpNested), diff --git a/hir/src/parser/ast/mod.rs b/hir/src/parser/ast/mod.rs index 35160179b..1362a407b 100644 --- a/hir/src/parser/ast/mod.rs +++ b/hir/src/parser/ast/mod.rs @@ -2,13 +2,11 @@ mod block; mod functions; mod globals; mod instruction; -mod types; pub use self::block::*; pub use self::functions::*; pub use self::globals::*; pub use self::instruction::*; -pub use self::types::*; use std::fmt; @@ -16,51 +14,8 @@ use miden_diagnostics::{SourceSpan, Span, Spanned}; use crate::Symbol; -/// This represents a fully parsed Miden IR program. -#[derive(Spanned)] -pub struct Program { - #[span] - pub span: SourceSpan, - /// The set of modules in the program - pub modules: Vec, - /// The name of the function that acts as the entry point for the program - pub entry_point: Option, - /// The global variables declared in this program - pub global_vars: Vec, -} -impl Program { - /// Creates a new [Program]. - pub fn new(span: SourceSpan, modules: Vec, globals: Vec) -> Self { - Self { - span: span, - modules: modules, - entry_point: None, - global_vars: globals, - } - } - - pub fn with_entry_point(&mut self, name: FunctionIdentifier) { - self.entry_point = Some(name) - } -} -impl fmt::Display for Program { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for module in self.modules.iter() { - writeln!(f, "{}", module)?; - } - writeln!(f)?; - if self.entry_point.is_some() { - writeln!(f, "{}", self.entry_point.as_ref().unwrap())?; - } - for global in self.global_vars.iter() { - writeln!(f, "{}", global)?; - } - Ok(()) - } -} - /// This is a type alias used to clarify that an identifier refers to a module -pub type ModuleId = Identifier; +pub type ModuleId = Ident; #[derive(Copy, Clone, PartialEq, Eq)] pub enum ModuleType { @@ -86,6 +41,7 @@ pub struct Module { pub span: SourceSpan, pub name: ModuleId, pub ty: ModuleType, + pub global_vars: Vec, pub functions: Vec, pub externals: Vec, } @@ -96,6 +52,7 @@ impl Module { span: SourceSpan, ty: ModuleType, name: ModuleId, + global_vars: Vec, functions: Vec, externals: Vec, ) -> Self { @@ -105,12 +62,16 @@ impl Module { ty, functions, externals, + global_vars, } } } impl fmt::Display for Module { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "{} {}", self.ty, self.name)?; + for gvar in self.global_vars.iter() { + writeln!(f, "{}", gvar)?; + } for func in self.functions.iter() { writeln!(f, "{}", func)?; } @@ -120,27 +81,3 @@ impl fmt::Display for Module { Ok(()) } } - -/// Represents any type of identifier in Miden IR. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Spanned)] -pub struct Identifier(Span); -impl Identifier { - pub fn new(span: SourceSpan, name: Symbol) -> Self { - Self(Span::new(span, name)) - } - - /// Returns the underlying symbol of the identifier. - pub fn name(&self) -> Symbol { - self.0.item - } - - #[inline] - pub fn as_str(&self) -> &str { - self.0.as_str() - } -} -impl fmt::Display for Identifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", &self.0) - } -} diff --git a/hir/src/parser/parser/grammar.lalrpop b/hir/src/parser/parser/grammar.lalrpop index c5dc422e5..82710cdd7 100644 --- a/hir/src/parser/parser/grammar.lalrpop +++ b/hir/src/parser/parser/grammar.lalrpop @@ -35,22 +35,12 @@ ColonColon: Vec = { // AST NODE // ================================================================================================ -pub Program: Program = { - => { - let mut p = Program::new(span!(l, r), modules, globals); - if let Some(name) = entry { - p.with_entry_point(name); - } - p - } -} - pub Module: Module = { - "kernel" => { - Module::new(span!(l, r), ModuleType::Kernel, name, functions, externals) + "kernel" => { + Module::new(span!(l, r), ModuleType::Kernel, name, globals, functions, externals) }, - "module" => { - Module::new(span!(l, r), ModuleType::Module, name, functions, externals) + "module" => { + Module::new(span!(l, r), ModuleType::Module, name, globals, functions, externals) }, } @@ -115,24 +105,24 @@ ExternalFunction: FunctionSignature = { ";" => signature } -CallConvention: CallConvention = { - "cc" "(" "fast" ")" => CallConvention::Fast, - "cc" "(" "kernel" ")" => CallConvention::Kernel, +CallConvention: CallConv = { + "cc" "(" "fast" ")" => CallConv::Fast, + "cc" "(" "kernel" ")" => CallConv::Kernel, } -ParamPurpose: ParameterPurpose = { - => ParameterPurpose::Standard, - "sret" => ParameterPurpose::Sret +ParamPurpose: ArgumentPurpose = { + => ArgumentPurpose::Default, + "sret" => ArgumentPurpose::StructReturn, } -ParamExtension: ParameterExtension = { - "zext" => ParameterExtension::Zero, - "sext" => ParameterExtension::Signed, +ParamExtension: ArgumentExtension = { + "zext" => ArgumentExtension::Zext, + "sext" => ArgumentExtension::Sext, } FunctionReturn: FunctionReturn = { => { - let ext = if let Some(e) = extension { e } else { ParameterExtension::None }; + let ext = if let Some(e) = extension { e } else { ArgumentExtension::None }; FunctionReturn::new(ext, ty) } } @@ -143,7 +133,7 @@ FunctionReturnSignature: Vec = { FunctionParam: FunctionParameter = { => { - let ext = if let Some(e) = extension { e } else { ParameterExtension::None }; + let ext = if let Some(e) = extension { e } else { ArgumentExtension::None }; FunctionParameter::new(purpose, ext, ty) } } @@ -155,12 +145,12 @@ FunctionParams: Vec = { FunctionSignature: FunctionSignature = { "pub" "fn" => { - let cc = if let Some(cc) = call_convention { cc } else { CallConvention::Default }; + let cc = if let Some(cc) = call_convention { cc } else { CallConv::SystemV }; let ret = if let Some(r) = returns { r } else { Vec::new() }; FunctionSignature::new(span!(l, r), Visibility::Public, cc, name, params, ret) }, "fn" => { - let cc = if let Some(cc) = call_convention { cc } else { CallConvention::Default }; + let cc = if let Some(cc) = call_convention { cc } else { CallConv::SystemV }; let ret = if let Some(r) = returns { r } else { Vec::new() }; FunctionSignature::new(span!(l, r), Visibility::Private, cc, name, params, ret) }, @@ -595,16 +585,16 @@ Immediate: Immediate = { "-" => Immediate::Neg(val), } -Identifier: Identifier = { - => Identifier::new(span!(l, r), name) +Identifier: Ident = { + => Ident::new(span!(l, r), name) } Value: Value = { => Value::new(id) } -FunctionIdentifier: FunctionIdentifier = { - > => FunctionIdentifier::new(span!(l, r), names) +FunctionIdentifier: FunctionIdent = { + > => FunctionIdent::new(span!(l, r), names) } From c9cbfe0c54533906b3f95ac0e6b46d9d75bd924a Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Fri, 20 Oct 2023 19:55:57 +0200 Subject: [PATCH 05/12] Treat FunctionIdent as a single lexer token --- hir/src/parser/lexer/mod.rs | 49 ++++++++++++++++++++------- hir/src/parser/parser/grammar.lalrpop | 13 ++----- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/hir/src/parser/lexer/mod.rs b/hir/src/parser/lexer/mod.rs index e43a48e34..278f0953e 100644 --- a/hir/src/parser/lexer/mod.rs +++ b/hir/src/parser/lexer/mod.rs @@ -76,6 +76,8 @@ pub enum Token { /// Identifiers should start with alphabet followed by one or more alpha numeric characters /// or an underscore. Ident(Symbol), + /// Function identifiers should be a non-empty sequence of identifiers separated by double colons "::". + FuncIdent(Symbol), /// Integers should only contain numeric characters. Num(u128), /// Hex strings are used to initialize global variables @@ -303,7 +305,6 @@ pub enum Token { // -------------------------------------------------------------------------------------------- DoubleQuote, Colon, - ColonColon, Semicolon, Comma, Dot, @@ -460,6 +461,11 @@ impl PartialEq for Token { return i == i2; } } + Self::FuncIdent(i) => { + if let Self::FuncIdent(i2) = other { + return i == i2; + } + } _ => return mem::discriminant(self) == mem::discriminant(other), } false @@ -472,6 +478,7 @@ impl fmt::Display for Token { Self::Error(_) => write!(f, "ERROR"), Self::Comment => write!(f, "COMMENT"), Self::Ident(ref id) => write!(f, "{}", id), + Self::FuncIdent(ref id) => write!(f, "{}", id), Self::Num(ref i) => write!(f, "{}", i), Self::Hex(ref data) => { write!(f, "0x")?; @@ -594,7 +601,6 @@ impl fmt::Display for Token { Self::Mut => write!(f, "mut"), Self::DoubleQuote => write!(f, "\""), Self::Colon => write!(f, ":"), - Self::ColonColon => write!(f, "::"), Self::Semicolon => write!(f, ";"), Self::Comma => write!(f, ","), Self::Dot => write!(f, "."), @@ -819,10 +825,7 @@ where match self.read() { ',' => pop!(self, Token::Comma), '.' => pop!(self, Token::Dot), - ':' => match self.peek() { - ':' => pop2!(self, Token::ColonColon), - _ => pop!(self, Token::Colon), - }, + ':' => pop!(self, Token::Colon), '"' => pop!(self, Token::DoubleQuote), '(' => pop!(self, Token::LParen), ')' => pop!(self, Token::RParen), @@ -890,9 +893,12 @@ where let c = self.pop(); debug_assert!(c.is_ascii_alphabetic() && c.is_lowercase()); - self.skip_ident(); - - Token::from_keyword_or_ident(self.slice()) + if self.skip_ident() { + Token::FuncIdent(Symbol::intern(self.slice())) + } + else { + Token::from_keyword_or_ident(self.slice()) + } } #[inline] @@ -900,19 +906,36 @@ where let c = self.pop(); debug_assert!(c.is_ascii_alphabetic()); - self.skip_ident(); - Token::Ident(Symbol::intern(self.slice())) + if self.skip_ident() { + Token::FuncIdent(Symbol::intern(self.slice())) + } + else { + Token::Ident(Symbol::intern(self.slice())) + } } - fn skip_ident(&mut self) { + // Returns true if the identifier is a function identifier (contains double colons), false otherwise + fn skip_ident(&mut self) -> bool { + let mut func_ident = false; loop { match self.read() { '_' => self.skip(), '0'..='9' => self.skip(), + ':' => { + match self.peek() { + ':' => { + func_ident = true; + self.skip(); + self.skip() + }, + _ => break, + } + } c if c.is_ascii_alphabetic() => self.skip(), _ => break, } - } + }; + func_ident } #[inline] diff --git a/hir/src/parser/parser/grammar.lalrpop b/hir/src/parser/parser/grammar.lalrpop index 82710cdd7..0a332d34d 100644 --- a/hir/src/parser/parser/grammar.lalrpop +++ b/hir/src/parser/parser/grammar.lalrpop @@ -23,15 +23,6 @@ Comma: Vec = { } }; -// ColonColon-delimited with at least one element -ColonColon: Vec = { - "::")*> => { - let mut v = v; - v.push(e); - v - } -}; - // AST NODE // ================================================================================================ @@ -594,7 +585,7 @@ Value: Value = { } FunctionIdentifier: FunctionIdent = { - > => FunctionIdent::new(span!(l, r), names) + => FunctionIdent::new(span!(l, r), func_identifier) } @@ -608,6 +599,7 @@ extern { enum Token { identifier => Token::Ident(), + func_identifier => Token::FuncIdent(), int => Token::Num(), hex => Token::Hex(>), "kernel" => Token::Kernel, @@ -732,7 +724,6 @@ extern { "&" => Token::Ampersand, "!" => Token::Bang, ":" => Token::Colon, - "::" => Token::ColonColon, ";" => Token::Semicolon, "," => Token::Comma, "[" => Token::LBracket, From e9d237009ea3faf4f99291d619731987d2357934 Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Sat, 21 Oct 2023 00:16:31 +0200 Subject: [PATCH 06/12] Make the parser use crate-level definitions --- Cargo.lock | 11 +++++++ hir/Cargo.toml | 1 + hir/src/instruction.rs | 10 ++++++ hir/src/lib.rs | 4 +++ hir/src/parser/ast/block.rs | 1 + hir/src/parser/ast/functions.rs | 1 + hir/src/parser/ast/globals.rs | 20 +----------- hir/src/parser/ast/instruction.rs | 21 +----------- hir/src/parser/ast/mod.rs | 4 +-- hir/src/parser/lexer/mod.rs | 10 ++---- hir/src/parser/{lib.rs => mod.rs} | 16 ++++----- hir/src/parser/parser/grammar.lalrpop | 21 +++++------- hir/src/parser/parser/mod.rs | 47 ++------------------------- 13 files changed, 52 insertions(+), 115 deletions(-) rename hir/src/parser/{lib.rs => mod.rs} (88%) diff --git a/Cargo.lock b/Cargo.lock index 787162f67..f2fd5c474 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,6 +903,7 @@ dependencies = [ "miden-diagnostics", "miden-hir-symbol", "miden-hir-type", + "miden-parsing", "paste", "petgraph", "rustc-hash", @@ -963,6 +964,16 @@ dependencies = [ "smallvec", ] +[[package]] +name = "miden-parsing" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d36dfec2c0319b3773a83627318f92a0212077bed80148c86e8b09af60cd1a88" +dependencies = [ + "miden-diagnostics", + "thiserror", +] + [[package]] name = "midenc" version = "0.1.0" diff --git a/hir/Cargo.toml b/hir/Cargo.toml index 010dc883a..3e11ff6c5 100644 --- a/hir/Cargo.toml +++ b/hir/Cargo.toml @@ -22,6 +22,7 @@ miden-assembly.workspace = true miden-diagnostics.workspace = true miden-hir-symbol.workspace = true miden-hir-type.workspace = true +miden-parsing = "0.1" petgraph = "0.6" paste.workspace = true rustc-hash.workspace = true diff --git a/hir/src/instruction.rs b/hir/src/instruction.rs index 8c74e0b20..a7b5fd9d7 100644 --- a/hir/src/instruction.rs +++ b/hir/src/instruction.rs @@ -809,6 +809,16 @@ impl Overflow { matches!(self, Self::Overflowing) } } +impl fmt::Display for Overflow { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Unchecked => f.write_str("unchecked"), + Self::Checked => f.write_str("checked"), + Self::Wrapping => f.write_str("wrapping"), + Self::Overflowing => f.write_str("overflow"), + } + } +} #[derive(Debug, Clone)] pub struct GlobalValueOp { diff --git a/hir/src/lib.rs b/hir/src/lib.rs index f7a43ac98..542522146 100644 --- a/hir/src/lib.rs +++ b/hir/src/lib.rs @@ -1,4 +1,8 @@ #![deny(warnings)] +mod parser; + +#[macro_use] +extern crate lalrpop_util; pub use intrusive_collections::UnsafeRef; pub use miden_diagnostics::SourceSpan; diff --git a/hir/src/parser/ast/block.rs b/hir/src/parser/ast/block.rs index dc0e85fb2..85575bf9f 100644 --- a/hir/src/parser/ast/block.rs +++ b/hir/src/parser/ast/block.rs @@ -1,3 +1,4 @@ +use crate::{Ident, Type, }; use super::*; const INDENT: &str = " "; diff --git a/hir/src/parser/ast/functions.rs b/hir/src/parser/ast/functions.rs index 313b18217..521587a85 100644 --- a/hir/src/parser/ast/functions.rs +++ b/hir/src/parser/ast/functions.rs @@ -1,3 +1,4 @@ +use crate::{ArgumentPurpose, ArgumentExtension, CallConv, FunctionIdent, Type, }; use super::*; /// The possible visibilities of a function diff --git a/hir/src/parser/ast/globals.rs b/hir/src/parser/ast/globals.rs index 32b7d0708..41f1a1422 100644 --- a/hir/src/parser/ast/globals.rs +++ b/hir/src/parser/ast/globals.rs @@ -2,6 +2,7 @@ use std::fmt; use miden_diagnostics::{SourceSpan, Spanned}; +use crate::{Ident, Linkage, Type, }; use super::*; /// This is a type alias used to clarify that an identifier refers to a global variable @@ -68,22 +69,3 @@ impl fmt::Display for GlobalVarDeclaration { Ok(()) } } -/// Represents the intended linkage for a global variable. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum Linkage { - /// Global linkage - Internal, - /// "One definition rule" linkage - Odr, - /// External linkage - External, -} -impl fmt::Display for Linkage { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Internal => write!(f, "internal"), - Self::Odr => write!(f, "odr"), - Self::External => write!(f, "external"), - } - } -} diff --git a/hir/src/parser/ast/instruction.rs b/hir/src/parser/ast/instruction.rs index 8a62c95c4..f2048ba40 100644 --- a/hir/src/parser/ast/instruction.rs +++ b/hir/src/parser/ast/instruction.rs @@ -1,3 +1,4 @@ +use crate::{FunctionIdent, Ident, Overflow, Type, }; use super::*; /// Represents a value in Miden IR. @@ -410,7 +411,6 @@ pub enum UnaryImmOpCode { I16, I32, I64, - ISize, Felt, F64, } @@ -423,7 +423,6 @@ impl fmt::Display for UnaryImmOpCode { Self::I16 => f.write_str("i16"), Self::I32 => f.write_str("i32"), Self::I64 => f.write_str("i64"), - Self::ISize => f.write_str("isize"), Self::Felt => f.write_str("felt"), Self::F64 => f.write_str("f64"), } @@ -544,24 +543,6 @@ impl fmt::Display for GlobalValueOp { } } -/// Used to distinguish between top-level global value operations -pub enum Overflow { - Checked, - Unchecked, - Overflowing, - Wrapping, -} -impl fmt::Display for Overflow { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Checked => f.write_str("checked"), - Self::Unchecked => f.write_str("unchecked"), - Self::Overflowing => f.write_str("overflowing"), - Self::Wrapping => f.write_str("wrapping"), - } - } -} - /// The destination of a branch/jump pub struct Destination { pub label: Label, diff --git a/hir/src/parser/ast/mod.rs b/hir/src/parser/ast/mod.rs index 1362a407b..cdf6a0bc0 100644 --- a/hir/src/parser/ast/mod.rs +++ b/hir/src/parser/ast/mod.rs @@ -10,9 +10,9 @@ pub use self::instruction::*; use std::fmt; -use miden_diagnostics::{SourceSpan, Span, Spanned}; +use miden_diagnostics::{SourceSpan, Spanned}; -use crate::Symbol; +use crate::Ident; /// This is a type alias used to clarify that an identifier refers to a module pub type ModuleId = Ident; diff --git a/hir/src/parser/lexer/mod.rs b/hir/src/parser/lexer/mod.rs index 278f0953e..13da3d871 100644 --- a/hir/src/parser/lexer/mod.rs +++ b/hir/src/parser/lexer/mod.rs @@ -97,7 +97,7 @@ pub enum Token { External, /// Keyword to declare that a function is publicly visible. Pub, - /// Keyword to declare that a function is publicly visible. + /// Keyword to declare a function. Fn, /// Keyword to declare a function's calling convention. Cc, @@ -295,8 +295,6 @@ pub enum Token { I128, U128, U256, - ISize, - USize, F64, Felt, Mut, @@ -333,6 +331,7 @@ impl Token { "odr" => Self::Odr, "external" => Self::External, "pub" => Self::Pub, + "fn" => Self::Fn, "cc" => Self::Cc, "fast" => Self::Fast, "sret" => Self::Sret, @@ -433,8 +432,6 @@ impl Token { "i128" => Self::I128, "u128" => Self::U128, "u256" => Self::U256, - "isize" => Self::ISize, - "usize" => Self::USize, "f64" => Self::F64, "felt" => Self::Felt, "mut" => Self::Mut, @@ -594,8 +591,6 @@ impl fmt::Display for Token { Self::I128 => write!(f, "i128"), Self::U128 => write!(f, "u128"), Self::U256 => write!(f, "u256"), - Self::ISize => write!(f, "isize"), - Self::USize => write!(f, "usize"), Self::F64 => write!(f, "f64"), Self::Felt => write!(f, "felt"), Self::Mut => write!(f, "mut"), @@ -826,6 +821,7 @@ where ',' => pop!(self, Token::Comma), '.' => pop!(self, Token::Dot), ':' => pop!(self, Token::Colon), + ';' => pop!(self, Token::Semicolon), '"' => pop!(self, Token::DoubleQuote), '(' => pop!(self, Token::LParen), ')' => pop!(self, Token::RParen), diff --git a/hir/src/parser/lib.rs b/hir/src/parser/mod.rs similarity index 88% rename from hir/src/parser/lib.rs rename to hir/src/parser/mod.rs index a78424e14..3560d36e7 100644 --- a/hir/src/parser/lib.rs +++ b/hir/src/parser/mod.rs @@ -1,13 +1,9 @@ -#[macro_use] -extern crate lalrpop_util; - pub mod ast; mod lexer; mod parser; -pub mod symbols; pub use self::parser::{ParseError, Parser}; -pub use self::symbols::Symbol; +use super::Symbol; use std::path::Path; use std::sync::Arc; @@ -19,9 +15,9 @@ pub fn parse( diagnostics: &DiagnosticsHandler, codemap: Arc, source: &str, -) -> Result { +) -> Result { let parser = Parser::new((), codemap); - match parser.parse_string::(diagnostics, source) { + match parser.parse_string::(diagnostics, source) { Ok(ast) => Ok(ast), Err(ParseError::Lexer(err)) => { diagnostics.emit(err); @@ -36,9 +32,9 @@ pub fn parse_file>( diagnostics: &DiagnosticsHandler, codemap: Arc, source: P, -) -> Result { +) -> Result { let parser = Parser::new((), codemap); - match parser.parse_file::(diagnostics, source) { + match parser.parse_file::(diagnostics, source) { Ok(ast) => Ok(ast), Err(ParseError::Lexer(err)) => { diagnostics.emit(err); @@ -51,7 +47,7 @@ pub fn parse_file>( /// Parses the provided source string with a default [CodeMap] and [DiagnosticsHandler]. /// /// This is primarily provided for use in tests, you should generally prefer [parse] -pub fn parse_str(source: &str) -> Result { +pub fn parse_str(source: &str) -> Result { use miden_diagnostics::{ term::termcolor::ColorChoice, DefaultEmitter, DiagnosticsConfig, Verbosity, }; diff --git a/hir/src/parser/parser/grammar.lalrpop b/hir/src/parser/parser/grammar.lalrpop index 0a332d34d..5289a40dd 100644 --- a/hir/src/parser/parser/grammar.lalrpop +++ b/hir/src/parser/parser/grammar.lalrpop @@ -1,8 +1,10 @@ use std::sync::Arc; +use std::str::FromStr; use miden_diagnostics::{CodeMap, DiagnosticsHandler}; -use crate::{ +use crate::{AddressSpace, ArgumentPurpose, ArgumentExtension, CallConv, FunctionIdent, Ident, Linkage, Overflow, StructType, Type, }; +use crate::parser::{ ast::*, lexer::Token, parser::ParseError, @@ -78,15 +80,13 @@ Type: Type = { "i128" => Type::I128, "u128" => Type::U128, "u256" => Type::U256, - "isize" => Type::ISize, - "usize" => Type::USize, "f64" => Type::F64, "felt" => Type::Felt, "*" "mut" => Type::Ptr(Box::new(inner)), - "&" "mut" => Type::NativePtr(Box::new(inner)), - "{" > "}" => Type::Struct(field_types), - "{" "}" => Type::Struct(Vec::new()), - "[" ";" "]" => Type::Array(Box::new(inner), length), + "&" "mut" => Type::NativePtr(Box::new(inner), AddressSpace::Unknown), + "{" > "}" => Type::Struct(StructType::new(field_types)), + "{" "}" => Type::Struct(StructType::new(Vec::new())), + "[" ";" "]" => Type::Array(Box::new(inner), usize::try_from(length).unwrap()), } // FUNCTIONS @@ -387,7 +387,6 @@ UnaryImmOpCode: UnaryImmOpCode = { "const" "." "i16" => UnaryImmOpCode::I16, "const" "." "i32" => UnaryImmOpCode::I32, "const" "." "i64" => UnaryImmOpCode::I64, - "const" "." "isize" => UnaryImmOpCode::ISize, "const" "." "felt" => UnaryImmOpCode::Felt, "const" "." "f64" => UnaryImmOpCode::F64, } @@ -577,7 +576,7 @@ Immediate: Immediate = { } Identifier: Ident = { - => Ident::new(span!(l, r), name) + => Ident::new(name, span!(l, r)) } Value: Value = { @@ -585,7 +584,7 @@ Value: Value = { } FunctionIdentifier: FunctionIdent = { - => FunctionIdent::new(span!(l, r), func_identifier) + => FunctionIdent::from_str(name.as_str()).unwrap() } @@ -705,8 +704,6 @@ extern { "i128" => Token::I128, "u128" => Token::U128, "u256" => Token::U256, - "isize" => Token::ISize, - "usize" => Token::USize, "f64" => Token::F64, "felt" => Token::Felt, "mut" => Token::Mut, diff --git a/hir/src/parser/parser/mod.rs b/hir/src/parser/parser/mod.rs index 2b0a30097..c645f33a3 100644 --- a/hir/src/parser/parser/mod.rs +++ b/hir/src/parser/parser/mod.rs @@ -11,7 +11,7 @@ macro_rules! span { lalrpop_mod!( #[allow(clippy::all)] grammar, - "/parser/grammar.rs" + "/parser/parser/grammar.rs" ); use std::sync::Arc; @@ -21,7 +21,7 @@ use miden_diagnostics::{ }; use miden_parsing::{Scanner, Source}; -use crate::{ +use crate::parser::{ ast, lexer::{Lexed, Lexer, LexicalError, Token}, }; @@ -170,49 +170,6 @@ impl ToDiagnostic for ParseError { } } -impl miden_parsing::Parse for ast::Program { - type Parser = grammar::ProgramParser; - type Error = ParseError; - type Config = (); - type Token = Lexed; - - fn root_file_error(source: std::io::Error, path: std::path::PathBuf) -> Self::Error { - ParseError::FileError { source, path } - } - - fn parse( - parser: &Parser, - diagnostics: &DiagnosticsHandler, - source: S, - ) -> Result - where - S: Source, - { - let scanner = Scanner::new(source); - let lexer = Lexer::new(scanner); - Self::parse_tokens(diagnostics, parser.codemap.clone(), lexer) - } - - fn parse_tokens>( - diagnostics: &DiagnosticsHandler, - codemap: Arc, - tokens: S, - ) -> Result { - let mut next_var = 0; - let result = Self::Parser::new().parse(diagnostics, &codemap, &mut next_var, tokens); - match result { - Ok(ast) => { - if diagnostics.has_errors() { - return Err(ParseError::Failed); - } - Ok(ast) - } - Err(lalrpop_util::ParseError::User { error }) => Err(error), - Err(err) => Err(err.into()), - } - } -} - impl miden_parsing::Parse for ast::Module { type Parser = grammar::ModuleParser; type Error = ParseError; From cfcaaa8b737a77540d84f8ccefc90a8c2b812d1a Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Sat, 21 Oct 2023 00:22:36 +0200 Subject: [PATCH 07/12] clippy --- hir/src/parser/ast/block.rs | 4 ++-- hir/src/parser/ast/functions.rs | 2 +- hir/src/parser/ast/globals.rs | 10 +++++----- hir/src/parser/ast/instruction.rs | 6 +++--- hir/src/parser/lexer/mod.rs | 24 ++++++++++-------------- hir/src/write.rs | 9 +++------ 6 files changed, 24 insertions(+), 31 deletions(-) diff --git a/hir/src/parser/ast/block.rs b/hir/src/parser/ast/block.rs index 85575bf9f..9e33b7c68 100644 --- a/hir/src/parser/ast/block.rs +++ b/hir/src/parser/ast/block.rs @@ -1,5 +1,5 @@ -use crate::{Ident, Type, }; use super::*; +use crate::{Ident, Type}; const INDENT: &str = " "; @@ -49,7 +49,7 @@ impl BlockHeader { impl fmt::Display for BlockHeader { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} ", self.label)?; - if self.args.len() == 0 { + if self.args.is_empty() { f.write_str(":\n") } else { f.write_str("(")?; diff --git a/hir/src/parser/ast/functions.rs b/hir/src/parser/ast/functions.rs index 521587a85..332c83df6 100644 --- a/hir/src/parser/ast/functions.rs +++ b/hir/src/parser/ast/functions.rs @@ -1,5 +1,5 @@ -use crate::{ArgumentPurpose, ArgumentExtension, CallConv, FunctionIdent, Type, }; use super::*; +use crate::{ArgumentExtension, ArgumentPurpose, CallConv, FunctionIdent, Type}; /// The possible visibilities of a function pub enum Visibility { diff --git a/hir/src/parser/ast/globals.rs b/hir/src/parser/ast/globals.rs index 41f1a1422..42ec9f846 100644 --- a/hir/src/parser/ast/globals.rs +++ b/hir/src/parser/ast/globals.rs @@ -2,8 +2,8 @@ use std::fmt; use miden_diagnostics::{SourceSpan, Spanned}; -use crate::{Ident, Linkage, Type, }; use super::*; +use crate::{Ident, Linkage, Type}; /// This is a type alias used to clarify that an identifier refers to a global variable pub type GlobalVarId = Ident; @@ -48,10 +48,10 @@ impl GlobalVarDeclaration { /// pub fn new(span: SourceSpan, name: ModuleId, ty: Type, linkage: Linkage) -> Self { Self { - span: span, - name: name, - ty: ty, - linkage: linkage, + span, + name, + ty, + linkage, init: None, } } diff --git a/hir/src/parser/ast/instruction.rs b/hir/src/parser/ast/instruction.rs index f2048ba40..034d2c8f1 100644 --- a/hir/src/parser/ast/instruction.rs +++ b/hir/src/parser/ast/instruction.rs @@ -1,5 +1,5 @@ -use crate::{FunctionIdent, Ident, Overflow, Type, }; use super::*; +use crate::{FunctionIdent, Ident, Overflow, Type}; /// Represents a value in Miden IR. /// @@ -59,7 +59,7 @@ impl Instruction { } impl fmt::Display for Instruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.values.len() == 0 { + if self.values.is_empty() { write!(f, "{}", self.op)?; } else { for (i, v) in self.values.iter().enumerate() { @@ -556,7 +556,7 @@ impl Destination { impl fmt::Display for Destination { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.label)?; - if self.args.len() > 0 { + if !self.args.is_empty() { f.write_str(" (")?; for (i, arg) in self.args.iter().enumerate() { if i > 0 { diff --git a/hir/src/parser/lexer/mod.rs b/hir/src/parser/lexer/mod.rs index 13da3d871..83c63e90c 100644 --- a/hir/src/parser/lexer/mod.rs +++ b/hir/src/parser/lexer/mod.rs @@ -891,8 +891,7 @@ where if self.skip_ident() { Token::FuncIdent(Symbol::intern(self.slice())) - } - else { + } else { Token::from_keyword_or_ident(self.slice()) } } @@ -904,8 +903,7 @@ where if self.skip_ident() { Token::FuncIdent(Symbol::intern(self.slice())) - } - else { + } else { Token::Ident(Symbol::intern(self.slice())) } } @@ -917,20 +915,18 @@ where match self.read() { '_' => self.skip(), '0'..='9' => self.skip(), - ':' => { - match self.peek() { - ':' => { - func_ident = true; - self.skip(); - self.skip() - }, - _ => break, + ':' => match self.peek() { + ':' => { + func_ident = true; + self.skip(); + self.skip() } - } + _ => break, + }, c if c.is_ascii_alphabetic() => self.skip(), _ => break, } - }; + } func_ident } diff --git a/hir/src/write.rs b/hir/src/write.rs index 65504d7dc..4b4033f28 100644 --- a/hir/src/write.rs +++ b/hir/src/write.rs @@ -175,11 +175,10 @@ fn write_operands( Instruction::Ret(Ret { args, .. }) => { if args.len(pool) > 0 { write!(w, " ({})", DisplayValues(args.as_slice(pool))) - } - else { + } else { Ok(()) } - }, + } Instruction::RetImm(RetImm { arg, .. }) => write!(w, " {arg}"), Instruction::Call(Call { callee, args, .. }) => { write!(w, " {}({})", callee, DisplayValues(args.as_slice(pool))) @@ -197,9 +196,7 @@ fn write_operands( write_block_args(w, else_dest.1.as_slice(pool)) } Instruction::Br(Br { - destination, - args, - .. + destination, args, .. }) => { write!(w, " {}", destination)?; write_block_args(w, args.as_slice(pool)) From 977f13dfcd9897dd036ebe0888921e3531170175 Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Mon, 23 Oct 2023 14:15:21 +0200 Subject: [PATCH 08/12] Added CommaOpt meta-rule, simplified grammar to use CommaOpt --- hir/src/parser/parser/grammar.lalrpop | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/hir/src/parser/parser/grammar.lalrpop b/hir/src/parser/parser/grammar.lalrpop index 5289a40dd..9e6ddfba2 100644 --- a/hir/src/parser/parser/grammar.lalrpop +++ b/hir/src/parser/parser/grammar.lalrpop @@ -25,6 +25,15 @@ Comma: Vec = { } }; +// Comma-delimited, possibly empty, possibly with a trailing comma +CommaOpt: Vec = { + ",")*> => { + let mut v = v; + v.extend(e); + v + } +}; + // AST NODE // ================================================================================================ @@ -84,8 +93,7 @@ Type: Type = { "felt" => Type::Felt, "*" "mut" => Type::Ptr(Box::new(inner)), "&" "mut" => Type::NativePtr(Box::new(inner), AddressSpace::Unknown), - "{" > "}" => Type::Struct(StructType::new(field_types)), - "{" "}" => Type::Struct(StructType::new(Vec::new())), + "{" > "}" => Type::Struct(StructType::new(field_types)), "[" ";" "]" => Type::Array(Box::new(inner), usize::try_from(length).unwrap()), } @@ -130,8 +138,7 @@ FunctionParam: FunctionParameter = { } FunctionParams: Vec = { - "(" ")" => Vec::new(), - "(" > ")" => params, + "(" > ")" => params, } FunctionSignature: FunctionSignature = { @@ -493,12 +500,9 @@ Operation: Operation = { "ret" => { Operation::ReturnOp(Vec::new()) }, - "(" > ")" => { + "(" > ")" => { Operation::CallOp(op, f, args) }, - "(" ")" => { - Operation::CallOp(op, f, Vec::new()) - }, "cond" "," "," => { Operation::CondOp(val, dest1, dest2) }, From 865746f237cf27341850892d06e8432fb6e57678 Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Mon, 23 Oct 2023 17:13:10 +0200 Subject: [PATCH 09/12] Eliminate dead code warnings --- hir/src/lib.rs | 2 +- hir/src/parser/mod.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/hir/src/lib.rs b/hir/src/lib.rs index 542522146..f6fcfd89d 100644 --- a/hir/src/lib.rs +++ b/hir/src/lib.rs @@ -1,5 +1,5 @@ #![deny(warnings)] -mod parser; +pub mod parser; #[macro_use] extern crate lalrpop_util; diff --git a/hir/src/parser/mod.rs b/hir/src/parser/mod.rs index 3560d36e7..38fd96f86 100644 --- a/hir/src/parser/mod.rs +++ b/hir/src/parser/mod.rs @@ -67,6 +67,7 @@ pub fn parse_str(source: &str) -> Result { /// Parses a [Module] from the given path. /// /// This is primarily intended for use in the import resolution phase. +#[allow(dead_code)] pub(crate) fn parse_module_from_file>( diagnostics: &DiagnosticsHandler, codemap: Arc, @@ -86,6 +87,7 @@ pub(crate) fn parse_module_from_file>( /// Parses a [Module] from a file already in the codemap /// /// This is primarily intended for use in the import resolution phase. +#[allow(dead_code)] pub(crate) fn parse_module( diagnostics: &DiagnosticsHandler, codemap: Arc, From 2f2317c16af9ee66eba08b0d92d4456cdc443ffc Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Tue, 24 Oct 2023 22:12:34 +0200 Subject: [PATCH 10/12] Simple test added --- Cargo.lock | 1 + hir/Cargo.toml | 1 + hir/src/parser/ast/block.rs | 11 +- hir/src/parser/ast/functions.rs | 22 +- hir/src/parser/ast/globals.rs | 10 +- hir/src/parser/ast/instruction.rs | 23 +- hir/src/parser/ast/mod.rs | 13 +- hir/src/parser/parser/mod.rs | 3 + hir/src/parser/parser/tests/input/system.mir | 12 + hir/src/parser/parser/tests/mod.rs | 753 +++++++++++++++++++ hir/src/parser/parser/tests/utils.rs | 156 ++++ 11 files changed, 998 insertions(+), 7 deletions(-) create mode 100644 hir/src/parser/parser/tests/input/system.mir create mode 100644 hir/src/parser/parser/tests/mod.rs create mode 100644 hir/src/parser/parser/tests/utils.rs diff --git a/Cargo.lock b/Cargo.lock index f2fd5c474..3a426243c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -906,6 +906,7 @@ dependencies = [ "miden-parsing", "paste", "petgraph", + "pretty_assertions", "rustc-hash", "smallvec", "thiserror", diff --git a/hir/Cargo.toml b/hir/Cargo.toml index 3e11ff6c5..2ecaefa88 100644 --- a/hir/Cargo.toml +++ b/hir/Cargo.toml @@ -25,6 +25,7 @@ miden-hir-type.workspace = true miden-parsing = "0.1" petgraph = "0.6" paste.workspace = true +pretty_assertions = "1.0" rustc-hash.workspace = true smallvec.workspace = true thiserror.workspace = true diff --git a/hir/src/parser/ast/block.rs b/hir/src/parser/ast/block.rs index 9e33b7c68..e15ec1373 100644 --- a/hir/src/parser/ast/block.rs +++ b/hir/src/parser/ast/block.rs @@ -6,6 +6,7 @@ const INDENT: &str = " "; /// Represents the label at the start of a basic block. /// /// Labels must be unique within each function. +#[derive(PartialEq, Debug)] pub struct Label { pub name: Ident, } @@ -21,6 +22,7 @@ impl fmt::Display for Label { } /// Represents an argument for a basic block +#[derive(PartialEq, Debug)] pub struct BlockArgument { pub value: Value, pub ty: Type, @@ -37,6 +39,7 @@ impl fmt::Display for BlockArgument { } /// Represents the label and the arguments of a basic block +#[derive(PartialEq, Debug)] pub struct BlockHeader { pub label: Label, pub args: Vec, @@ -66,7 +69,7 @@ impl fmt::Display for BlockHeader { } /// Represents a basic block of instructions -#[derive(Spanned)] +#[derive(Spanned, Debug)] pub struct Block { #[span] pub span: SourceSpan, @@ -82,6 +85,12 @@ impl Block { } } } +impl PartialEq for Block { + fn eq(&self, other: &Self) -> bool { + self.header == other.header + && self.instructions == other.instructions + } +} impl fmt::Display for Block { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "{}", self.header)?; diff --git a/hir/src/parser/ast/functions.rs b/hir/src/parser/ast/functions.rs index 332c83df6..83a42101c 100644 --- a/hir/src/parser/ast/functions.rs +++ b/hir/src/parser/ast/functions.rs @@ -2,6 +2,7 @@ use super::*; use crate::{ArgumentExtension, ArgumentPurpose, CallConv, FunctionIdent, Type}; /// The possible visibilities of a function +#[derive(PartialEq, Debug)] pub enum Visibility { /// (Module) private visibility Private, @@ -11,6 +12,7 @@ pub enum Visibility { /// A single parameter to a function. /// Parameter names are defined in the entry block for the function. +#[derive(PartialEq, Debug)] pub struct FunctionParameter { /// The purpose of the parameter (default or struct return) pub purpose: ArgumentPurpose, @@ -44,6 +46,7 @@ impl fmt::Display for FunctionParameter { } /// A single return value from a function. +#[derive(PartialEq, Debug)] pub struct FunctionReturn { /// The bit extension for the parameter pub extension: ArgumentExtension, @@ -67,7 +70,7 @@ impl fmt::Display for FunctionReturn { } /// Represents the type signature of a function -#[derive(Spanned)] +#[derive(Spanned, Debug)] pub struct FunctionSignature { #[span] pub span: SourceSpan, @@ -96,6 +99,15 @@ impl FunctionSignature { } } } +impl PartialEq for FunctionSignature { + fn eq(&self, other: &Self) -> bool { + self.visibility == other.visibility + && self.call_convention == other.call_convention + && self.name == other.name + && self.params == other.params + && self.returns == other.returns + } +} impl fmt::Display for FunctionSignature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.visibility { @@ -128,7 +140,7 @@ impl fmt::Display for FunctionSignature { } /// Represents the declaration of a function -#[derive(Spanned)] +#[derive(Spanned, Debug)] pub struct FunctionDeclaration { #[span] pub span: SourceSpan, @@ -144,6 +156,12 @@ impl FunctionDeclaration { } } } +impl PartialEq for FunctionDeclaration { + fn eq(&self, other: &Self) -> bool { + self.signature == other.signature + && self.blocks == other.blocks + } +} impl fmt::Display for FunctionDeclaration { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.signature)?; diff --git a/hir/src/parser/ast/globals.rs b/hir/src/parser/ast/globals.rs index 42ec9f846..d048b30cf 100644 --- a/hir/src/parser/ast/globals.rs +++ b/hir/src/parser/ast/globals.rs @@ -34,7 +34,7 @@ impl fmt::Display for GlobalVarInitializer { } /// This represents the declaration of a Miden IR global variable -#[derive(Spanned)] +#[derive(Spanned, Debug)] pub struct GlobalVarDeclaration { #[span] pub span: SourceSpan, @@ -60,6 +60,14 @@ impl GlobalVarDeclaration { self.init = Some(init) } } +impl PartialEq for GlobalVarDeclaration { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && self.ty == other.ty + && self.linkage == other.linkage + && self.init == other.init + } +} impl fmt::Display for GlobalVarDeclaration { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} {} {}", self.name, self.ty, self.linkage)?; diff --git a/hir/src/parser/ast/instruction.rs b/hir/src/parser/ast/instruction.rs index 034d2c8f1..b23ee8af4 100644 --- a/hir/src/parser/ast/instruction.rs +++ b/hir/src/parser/ast/instruction.rs @@ -5,6 +5,7 @@ use crate::{FunctionIdent, Ident, Overflow, Type}; /// /// All intermediate values are named, and have an associated [Value]. /// Value identifiers must be globally unique. +#[derive(PartialEq, Debug)] pub struct Value { pub name: Ident, } @@ -20,6 +21,7 @@ impl fmt::Display for Value { } /// Immediates are converted at a later stage +#[derive(PartialEq, Debug)] pub enum Immediate { Pos(u128), Neg(u128), @@ -39,7 +41,7 @@ impl fmt::Display for Immediate { /// An instruction consists of a single operation, and a number of values that /// represent the results of the operation. Additionally, the instruction contains /// the types of the produced results -#[derive(Spanned)] +#[derive(Spanned, Debug)] pub struct Instruction { #[span] pub span: SourceSpan, @@ -57,6 +59,13 @@ impl Instruction { } } } +impl PartialEq for Instruction { + fn eq(&self, other: &Self) -> bool { + self.values == other.values + && self.op == other.op + && self.types == other.types + } +} impl fmt::Display for Instruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.values.is_empty() { @@ -83,6 +92,7 @@ impl fmt::Display for Instruction { } /// Represents a operation and its arguments +#[derive(PartialEq, Debug)] pub enum Operation { BinaryOp(BinaryOpCode, Value, Value), BinaryImmOp(BinaryImmOpCode, Value, Immediate), @@ -179,6 +189,7 @@ impl fmt::Display for Operation { } /// Used to distinguish between user calls and kernel calls +#[derive(PartialEq, Debug)] pub enum CallOp { Call, SysCall, @@ -193,6 +204,7 @@ impl fmt::Display for CallOp { } /// Used to distinguish between binary operations +#[derive(PartialEq, Debug)] pub enum BinaryOpCode { Add(Overflow), Sub(Overflow), @@ -287,6 +299,7 @@ impl fmt::Display for BinaryOpCode { } /// Used to distinguish between immediate binary operations +#[derive(PartialEq, Debug)] pub enum BinaryImmOpCode { AddImm(Overflow), SubImm(Overflow), @@ -367,6 +380,7 @@ impl fmt::Display for BinaryImmOpCode { } /// Used to distinguish between unary operations +#[derive(PartialEq, Debug)] pub enum UnaryOpCode { Inv, Incr, @@ -405,6 +419,7 @@ impl fmt::Display for UnaryOpCode { } /// Used to distinguish between immediate unary operations +#[derive(PartialEq, Debug)] pub enum UnaryImmOpCode { I1, I8, @@ -430,6 +445,7 @@ impl fmt::Display for UnaryImmOpCode { } /// Used to distinguish between primary operations +#[derive(PartialEq, Debug)] pub enum PrimOpCode { Select, Assert, @@ -453,6 +469,7 @@ impl fmt::Display for PrimOpCode { /// Memory offset for global variable reads. /// Conversion to i32 happens during transformation to hir. +#[derive(PartialEq, Debug)] pub enum Offset { Pos(u128), Neg(u128), @@ -483,6 +500,7 @@ impl fmt::Display for Offset { } /// Used to distinguish between nested global value operations +#[derive(PartialEq, Debug)] pub enum GlobalValueOpNested { Symbol(Ident, Offset), Load(Box, Offset), @@ -511,6 +529,7 @@ impl fmt::Display for GlobalValueOpNested { } /// Used to distinguish between top-level global value operations +#[derive(PartialEq, Debug)] pub enum GlobalValueOp { Symbol(Ident, Offset), Load(GlobalValueOpNested, Offset), @@ -544,6 +563,7 @@ impl fmt::Display for GlobalValueOp { } /// The destination of a branch/jump +#[derive(PartialEq, Debug)] pub struct Destination { pub label: Label, pub args: Vec, @@ -572,6 +592,7 @@ impl fmt::Display for Destination { } /// A branch of a switch operation +#[derive(PartialEq, Debug)] pub enum SwitchBranch { Test(u128, Label), Default(Label), diff --git a/hir/src/parser/ast/mod.rs b/hir/src/parser/ast/mod.rs index cdf6a0bc0..6aa1a6c51 100644 --- a/hir/src/parser/ast/mod.rs +++ b/hir/src/parser/ast/mod.rs @@ -17,7 +17,7 @@ use crate::Ident; /// This is a type alias used to clarify that an identifier refers to a module pub type ModuleId = Ident; -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ModuleType { /// Kernel context module Kernel, @@ -35,7 +35,7 @@ impl fmt::Display for ModuleType { /// This represents the parsed contents of a single Miden IR module /// -#[derive(Spanned)] +#[derive(Spanned, Debug)] pub struct Module { #[span] pub span: SourceSpan, @@ -66,6 +66,15 @@ impl Module { } } } +impl PartialEq for Module { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + && self.ty == other.ty + && self.global_vars == other.global_vars + && self.functions == other.functions + && self.externals == other.externals + } +} impl fmt::Display for Module { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { writeln!(f, "{} {}", self.ty, self.name)?; diff --git a/hir/src/parser/parser/mod.rs b/hir/src/parser/parser/mod.rs index c645f33a3..24b5514f5 100644 --- a/hir/src/parser/parser/mod.rs +++ b/hir/src/parser/parser/mod.rs @@ -212,3 +212,6 @@ impl miden_parsing::Parse for ast::Module { } } } + +#[cfg(test)] +mod tests; diff --git a/hir/src/parser/parser/tests/input/system.mir b/hir/src/parser/parser/tests/input/system.mir new file mode 100644 index 000000000..797669a80 --- /dev/null +++ b/hir/src/parser/parser/tests/input/system.mir @@ -0,0 +1,12 @@ +module miden_ir_test + +global_1 u32 internal = 0xCAFEBABE + +pub cc(fast) fn miden_ir_test::test_func (zext u32, sext u32) -> u32 { + blk(v1 : u32, v2 : u32) : { + v3 = add.unchecked v1 v2 : u32 + ret (v1, v3) + } +} + +cc(kernel) fn exported::f1 (sret { u32, u32 }) -> [i8 ; 42]; diff --git a/hir/src/parser/parser/tests/mod.rs b/hir/src/parser/parser/tests/mod.rs new file mode 100644 index 000000000..7263d41c3 --- /dev/null +++ b/hir/src/parser/parser/tests/mod.rs @@ -0,0 +1,753 @@ +use crate::parser::ast::*; +use crate::{ArgumentExtension, ArgumentPurpose, CallConv, FunctionIdent, Ident, Linkage, Overflow, StructType, Type}; + +//macro_rules! assert_matches { +// ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { +// match $left { +// $( $pattern )|+ $( if $guard )? => {} +// ref left_val => { +// panic!(r#"assertion failed: `(left matches right)` +// left: `{:?}`, +// right: `{:?}`"#, +// left_val, stringify!($($pattern)|+ $(if $guard)?)); +// } +// } +// } +//} + +mod utils; +use self::utils::ParseTest; + +//macro_rules! assert_module_error { +// ($source:expr, $pattern:pat_param) => { +// if let Err(err) = ParseTest::new().parse_module($source) { +// assert_matches!(err, $pattern) +// } else { +// panic!("expected parsing to fail, but it succeeded"); +// } +// }; +//} + +macro_rules! ident { + ($name:ident) => { + Ident::new( + crate::Symbol::intern(stringify!($name)), + miden_diagnostics::SourceSpan::UNKNOWN, + ) + }; +// +// ($name:literal) => { +// Identifier::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// crate::Symbol::intern($name), +// ) +// }; +// +// ($module:ident, $name:ident) => { +// QualifiedIdentifier::new( +// ident!($module), +// NamespacedIdentifier::Binding(ident!($name)), +// ) +// }; +} + +macro_rules! function_ident { + ($module:ident, $name:ident) => { + FunctionIdent { + module: ident!($module), + function: ident!($name), + } + }; +} + +// +//#[allow(unused)] +//macro_rules! global { +// ($name:ident, $offset:literal, $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Global(ident!($name)), +// access_type: AccessType::Default, +// offset: $offset, +// ty: Some($ty), +// }) +// }; +// +// ($name:ident, $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Global(ident!($name)), +// access_type: AccessType::Default, +// offset: 0, +// ty: Some($ty), +// }) +// }; +// +// ($name:literal, $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Global(ident!($name)), +// access_type: AccessType::Default, +// offset: 0, +// ty: Some($ty), +// }) +// }; +//} +// +//macro_rules! access { +// ($name:ident) => { +// ScalarExpr::SymbolAccess(SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Default, +// 0, +// )) +// }; +// +// ($name:literal) => { +// ScalarExpr::SymbolAccess(SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Default, +// 0, +// )) +// }; +// +// ($module:ident, $name:ident, $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Resolved(ident!($module, $name)), +// access_type: AccessType::Default, +// offset: 0, +// ty: Some($ty), +// }) +// }; +// +// ($name:ident, $offset:literal) => { +// ScalarExpr::SymbolAccess(SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Default, +// $offset, +// )) +// }; +// +// ($name:literal, $offset:literal) => { +// ScalarExpr::SymbolAccess(SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Default, +// $offset, +// )) +// }; +// +// ($name:ident, $offset:literal, $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Local(ident!($name)), +// access_type: AccessType::Default, +// offset: $offset, +// ty: Some($ty), +// }) +// }; +// +// ($name:ident, $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Local(ident!($name)), +// access_type: AccessType::Default, +// offset: 0, +// ty: Some($ty), +// }) +// }; +// +// ($name:literal, $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Local(ident!($name)), +// access_type: AccessType::Default, +// offset: 0, +// ty: Some($ty), +// }) +// }; +// +// ($name:ident [ $idx:literal ]) => { +// ScalarExpr::SymbolAccess(SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Index($idx), +// 0, +// )) +// }; +// +// ($name:literal [ $idx:literal ]) => { +// ScalarExpr::SymbolAccess(SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Index($idx), +// 0, +// )) +// }; +// +// ($name:ident [ $row:literal ] [ $col:literal ]) => { +// ScalarExpr::SymbolAccess(SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Matrix($row, $col), +// 0, +// )) +// }; +// +// ($name:ident [ $row:literal ] [ $col:literal ], $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Local(ident!($name)), +// access_type: AccessType::Matrix($row, $col), +// offset: 0, +// ty: Some($ty), +// }) +// }; +// +// ($module:ident, $name:ident [ $idx:literal ], $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ident!($module, $name).into(), +// access_type: AccessType::Index($idx), +// offset: 0, +// ty: Some($ty), +// }) +// }; +// +// ($module:ident, $name:ident [ $row:literal ] [ $col:literal ], $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ident!($module, $name).into(), +// access_type: AccessType::Matrix($row, $col), +// offset: 0, +// ty: Some($ty), +// }) +// }; +// +// ($name:ident [ $idx:literal ], $offset:literal) => { +// ScalarExpr::SymbolAccess(SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Index($idx), +// $offset, +// )) +// }; +// +// ($name:ident [ $idx:literal ], $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Local(ident!($name)), +// access_type: AccessType::Index($idx), +// offset: 0, +// ty: Some($ty), +// }) +// }; +// +// ($name:ident [ $idx:literal ], $offset:literal, $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Local(ident!($name)), +// access_type: AccessType::Index($idx), +// offset: $offset, +// ty: Some($ty), +// }) +// }; +// +// ($name:literal [ $idx:literal ], $offset:literal) => { +// ScalarExpr::SymbolAccess(SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Index($idx), +// $offset, +// )) +// }; +//} +// +//macro_rules! expr { +// ($expr:expr) => { +// Expr::try_from($expr).unwrap() +// }; +//} +// +//macro_rules! slice { +// ($name:ident, $range:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Unresolved(NamespacedIdentifier::Binding(ident!($name))), +// access_type: AccessType::Slice($range), +// offset: 0, +// ty: None, +// }) +// }; +// +// ($name:ident, $range:expr, $ty:expr) => { +// ScalarExpr::SymbolAccess(SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Local(ident!($name)), +// access_type: AccessType::Slice($range), +// offset: 0, +// ty: Some($ty), +// }) +// }; +//} +// +//macro_rules! bounded_access { +// ($name:ident, $bound:expr) => { +// ScalarExpr::BoundedSymbolAccess(BoundedSymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Default, +// 0, +// ), +// $bound, +// )) +// }; +// +// ($name:ident, $bound:expr, $ty:expr) => { +// ScalarExpr::BoundedSymbolAccess(BoundedSymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Local(ident!($name)), +// access_type: AccessType::Default, +// offset: 0, +// ty: Some($ty), +// }, +// $bound, +// )) +// }; +// +// ($name:ident [ $idx:literal ], $bound:expr) => { +// ScalarExpr::BoundedSymbolAccess(BoundedSymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// SymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// ident!($name), +// AccessType::Index($idx), +// 0, +// ), +// $bound, +// )) +// }; +// +// ($name:ident [ $idx:literal ], $bound:expr, $ty:expr) => { +// ScalarExpr::BoundedSymbolAccess(BoundedSymbolAccess::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// SymbolAccess { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// name: ResolvableIdentifier::Local(ident!($name)), +// access_type: AccessType::Index($idx), +// offset: 0, +// ty: Some($ty), +// }, +// $bound, +// )) +// }; +//} +// +//macro_rules! int { +// ($value:literal) => { +// ScalarExpr::Const(miden_diagnostics::Span::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// $value, +// )) +// }; +// +// ($value:expr) => { +// ScalarExpr::Const(miden_diagnostics::Span::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// $value, +// )) +// }; +//} +// +//macro_rules! call { +// ($callee:ident ($($param:expr),+)) => { +// ScalarExpr::Call(Call::new(miden_diagnostics::SourceSpan::UNKNOWN, ident!($callee), vec![$($param),+])) +// }; +// +// ($module:ident :: $callee:ident ($($param:expr),+)) => { +// ScalarExpr::Call(Call { +// span: miden_diagnostics::SourceSpan::UNKNOWN, +// callee: ResolvableIdentifier::Resolved(function_ident!($module, $callee)), +// args: vec![$($param),+], +// ty: None, +// }) +// } +//} +// +//macro_rules! trace_segment { +// ($idx:literal, $name:literal, [$(($binding_name:ident, $binding_size:literal)),*]) => { +// TraceSegment::new(miden_diagnostics::SourceSpan::UNKNOWN, $idx, ident!($name), vec![ +// $(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, (ident!($binding_name), $binding_size))),* +// ]) +// } +//} +// +//macro_rules! random_values { +// ($name:literal, $size:literal) => { +// RandomValues::with_size(miden_diagnostics::SourceSpan::UNKNOWN, ident!($name), $size) +// }; +// +// ($name:literal, [$(($binding_name:ident, $binding_size:literal)),*]) => { +// RandomValues::new(miden_diagnostics::SourceSpan::UNKNOWN, ident!($name), vec![ +// $(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, (ident!($binding_name), $binding_size))),* +// ]) +// } +//} +// +//macro_rules! constant { +// ($name:ident = $value:literal) => { +// Constant::new( +// SourceSpan::UNKNOWN, +// ident!($name), +// ConstantExpr::Scalar($value), +// ) +// }; +// +// ($name:ident = [$($value:literal),+]) => { +// Constant::new(SourceSpan::UNKNOWN, ident!($name), ConstantExpr::Vector(vec![$($value),+])) +// }; +// +// ($name:ident = [$([$($value:literal),+]),+]) => { +// Constant::new(SourceSpan::UNKNOWN, ident!($name), ConstantExpr::Matrix(vec![$(vec![$($value),+]),+])) +// }; +//} +// +//macro_rules! vector { +// ($($value:literal),*) => { +// Expr::Const(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, ConstantExpr::Vector(vec![$($value),*]))) +// }; +// +// ($($value:expr),*) => { +// Expr::Vector(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, vec![$(expr!($value)),*])) +// } +//} +// +//macro_rules! matrix { +// ($([$($value:expr),+]),+) => { +// Expr::Matrix(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, vec![$(vec![$($value),+]),+])) +// }; +//} +// +//macro_rules! let_ { +// ($name:ident = $value:expr => $($body:expr),+) => { +// Statement::Let(Let::new(miden_diagnostics::SourceSpan::UNKNOWN, ident!($name), $value, vec![$($body),+])) +// }; +// +// ($name:literal = $value:expr => $($body:expr),+) => { +// Statement::Let(Let::new(miden_diagnostics::SourceSpan::UNKNOWN, ident!($name), $value, vec![$($body),+])) +// }; +//} +// +//macro_rules! enforce { +// ($expr:expr) => { +// Statement::Enforce($expr) +// }; +// +// ($expr:expr, when $selector:expr) => { +// Statement::EnforceIf($expr, $selector) +// }; +//} +// +//macro_rules! enforce_all { +// ($expr:expr) => { +// Statement::EnforceAll($expr) +// }; +//} +// +//macro_rules! lc { +// (($(($binding:ident, $iterable:expr)),+) => $body:expr) => {{ +// let context = vec![ +// $( +// (ident!($binding), $iterable) +// ),+ +// ]; +// ListComprehension::new(miden_diagnostics::SourceSpan::UNKNOWN, $body, context, None) +// }}; +// +// (($(($binding:literal, $iterable:expr)),+) => $body:expr) => {{ +// let context = vec![ +// $( +// (ident!($binding), $iterable) +// ),+ +// ]; +// ListComprehension::new(miden_diagnostics::SourceSpan::UNKNOWN, $body, context, None) +// }}; +// +// (($(($binding:ident, $iterable:expr)),*) => $body:expr, when $selector:expr) => {{ +// let context = vec![ +// $( +// (ident!($binding), $iterable) +// ),+ +// ]; +// ListComprehension::new(miden_diagnostics::SourceSpan::UNKNOWN, $body, context, Some($selector)) +// }}; +// +// (($(($binding:literal, $iterable:expr)),*) => $body:expr, when $selector:expr) => {{ +// let context = vec![ +// $( +// (ident!($binding), $iterable) +// ),+ +// ]; +// ListComprehension::new(miden_diagnostics::SourceSpan::UNKNOWN, $body, context, Some($selector)) +// }}; +//} +// +//macro_rules! range { +// ($range:expr) => { +// Expr::Range(miden_diagnostics::Span::new(SourceSpan::UNKNOWN, $range)) +// }; +//} +// +//macro_rules! and { +// ($lhs:expr, $rhs:expr) => { +// mul!($lhs, $rhs) +// }; +//} +// +//macro_rules! or { +// ($lhs:expr, $rhs:expr) => {{ +// sub!(add!($lhs, $rhs), mul!($lhs, $rhs)) +// }}; +//} +// +//macro_rules! not { +// ($rhs:expr) => { +// sub!(int!(1), $rhs) +// }; +//} +// +//macro_rules! eq { +// ($lhs:expr, $rhs:expr) => { +// ScalarExpr::Binary(BinaryExpr::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// BinaryOp::Eq, +// $lhs, +// $rhs, +// )) +// }; +//} +// +//macro_rules! add { +// ($lhs:expr, $rhs:expr) => { +// ScalarExpr::Binary(BinaryExpr::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// BinaryOp::Add, +// $lhs, +// $rhs, +// )) +// }; +//} +// +//macro_rules! sub { +// ($lhs:expr, $rhs:expr) => { +// ScalarExpr::Binary(BinaryExpr::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// BinaryOp::Sub, +// $lhs, +// $rhs, +// )) +// }; +//} +// +//macro_rules! mul { +// ($lhs:expr, $rhs:expr) => { +// ScalarExpr::Binary(BinaryExpr::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// BinaryOp::Mul, +// $lhs, +// $rhs, +// )) +// }; +//} +// +//macro_rules! exp { +// ($lhs:expr, $rhs:expr) => { +// ScalarExpr::Binary(BinaryExpr::new( +// miden_diagnostics::SourceSpan::UNKNOWN, +// BinaryOp::Exp, +// $lhs, +// $rhs, +// )) +// }; +//} +// +//macro_rules! import_all { +// ($module:ident) => { +// Import::All { +// module: ident!($module), +// } +// }; +//} +// +//macro_rules! import { +// ($module:ident, $item:ident) => {{ +// let mut items: std::collections::HashSet = std::collections::HashSet::default(); +// items.insert(ident!($item)); +// Import::Partial { +// module: ident!($module), +// items, +// } +// }}; +//} + +// FULL MIDEN IR FILE +// ================================================================================================ + +#[test] +fn full_mir_file() { + let dummy_sourcespan = miden_diagnostics::SourceSpan::UNKNOWN; + + // module miden_ir_test + let module_type = ModuleType::Module; + let module_name = ident!(miden_ir_test); + + // global_1 u32 internal = 0xCAFEBABE + let global_var_name = ident!(global_1); + let global_var_type = Type::U32; + let global_var_linkage = Linkage::Internal; + let mut global_var = GlobalVarDeclaration::new(dummy_sourcespan, + global_var_name, + global_var_type, + global_var_linkage); + let global_var_init_val : Vec = vec![b'C', b'A', b'F', b'E', b'B', b'A', b'B', b'E']; + let global_var_initializer = GlobalVarInitializer::new(global_var_init_val); + global_var.with_init(global_var_initializer); + let global_vars = vec![global_var]; + + // pub coc(fast) fn miden_ir_test::test_func (zext u32, sext u32) -> u32 { + let function_visibility = Visibility::Public; + let function_call_convention = CallConv::Fast; + let function_name = function_ident!(miden_ir_test, test_func); + + let fun_arg1_purpose = ArgumentPurpose::Default; + let fun_arg1_extension = ArgumentExtension::Zext; + let fun_arg1_type = Type::U32; + let fun_arg1 = FunctionParameter::new(fun_arg1_purpose, + fun_arg1_extension, + fun_arg1_type); + + let fun_arg2_purpose = ArgumentPurpose::Default; + let fun_arg2_extension = ArgumentExtension::Sext; + let fun_arg2_type = Type::U32; + let fun_arg2 = FunctionParameter::new(fun_arg2_purpose, + fun_arg2_extension, + fun_arg2_type); + let function_params = vec![fun_arg1, fun_arg2]; + + + let fun_return_extension = ArgumentExtension::None; + let fun_return_type = Type::U32; + let function_return = FunctionReturn::new(fun_return_extension, fun_return_type); + let function_returns = vec![function_return]; + + let function_signature = FunctionSignature::new(dummy_sourcespan, + function_visibility, + function_call_convention, + function_name, + function_params, + function_returns); + + // blk(v1 : u32, v2 : u32) : { + let block_label = Label::new(ident!(blk)); + + let block_arg1_name = Value::new(ident!(v1)); + let block_arg1_type = Type::U32; + let block_arg1 = BlockArgument::new(block_arg1_name, block_arg1_type); + + let block_arg2_name = Value::new(ident!(v2)); + let block_arg2_type = Type::U32; + let block_arg2 = BlockArgument::new(block_arg2_name, block_arg2_type); + + let block_args = vec![block_arg1, block_arg2]; + + let block_header = BlockHeader::new(block_label, block_args); + + // v3 = add.unchecked v1 v2 : u32 + let inst1_value = Value::new(ident!(v3)); + let inst1_values = vec![inst1_value]; + + let inst1_overflow = Overflow::Unchecked; + let inst1_opcode = BinaryOpCode::Add(inst1_overflow); + let inst1_operand1 = Value::new(ident!(v1)); + let inst1_operand2 = Value::new(ident!(v2)); + let inst1_op = Operation::BinaryOp(inst1_opcode, + inst1_operand1, + inst1_operand2); + let inst1_type = Type::U32; + let inst1_types : Vec = vec![inst1_type]; + let block_instruction1 = Instruction::new(dummy_sourcespan, + inst1_values, + inst1_op, + inst1_types); + + // ret (v1, v3) + let inst2_values : Vec = vec![]; + let inst2_return_val1 = Value::new(ident!(v1)); + let inst2_return_val2 = Value::new(ident!(v3)); + let inst2_return_vals = vec![inst2_return_val1, inst2_return_val2]; + let inst2_op = Operation::ReturnOp(inst2_return_vals); + let inst2_types : Vec = vec![]; + let block_instruction2 = Instruction::new(dummy_sourcespan, + inst2_values, + inst2_op, + inst2_types); + + let block_instructions = vec![block_instruction1, block_instruction2]; + + let block = Block::new(dummy_sourcespan, block_header, block_instructions); + let blocks = vec![block]; + + let function = FunctionDeclaration::new(dummy_sourcespan, + function_signature, + blocks); + let functions = vec![function]; + + // cc(kernel) fn exported::f1 (sret { u32, u32 }) -> [i8 ; 42]; + let external_visibility = Visibility::Private; + let external_call_convention = CallConv::Kernel; + let external_name = function_ident!(exported, f1); + + let ext_arg1_purpose = ArgumentPurpose::StructReturn; + let ext_arg1_extension = ArgumentExtension::None; + + let ext_arg1_type_field1 = Type::U32; + let ext_arg1_type_field2 = Type::U32; + let ext_arg1_type_fields = vec![ext_arg1_type_field1, ext_arg1_type_field2]; + let ext_arg1_type = Type::Struct(StructType::new(ext_arg1_type_fields)); + let ext_arg1 = FunctionParameter::new(ext_arg1_purpose, + ext_arg1_extension, + ext_arg1_type); + + let external_params = vec![ext_arg1]; + + let ext_return_extension = ArgumentExtension::None; + let ext_return_inner_type = Type::I8; + let ext_return_type = Type::Array(Box::new(ext_return_inner_type), 42); + let external_return = FunctionReturn::new(ext_return_extension, ext_return_type); + let external_returns = vec![external_return]; + + let external = FunctionSignature::new(dummy_sourcespan, + external_visibility, + external_call_convention, + external_name, + external_params, + external_returns); + let externals = vec![external]; + + let expected = Module::new(dummy_sourcespan, + module_type, + module_name, + global_vars, + functions, + externals); + + ParseTest::new().expect_module_ast_from_file("src/parser/parser/tests/input/system.mir", expected); +} diff --git a/hir/src/parser/parser/tests/utils.rs b/hir/src/parser/parser/tests/utils.rs new file mode 100644 index 000000000..e406fb73d --- /dev/null +++ b/hir/src/parser/parser/tests/utils.rs @@ -0,0 +1,156 @@ +use std::sync::Arc; + +use miden_diagnostics::{CodeMap, DiagnosticsConfig, DiagnosticsHandler, Emitter, Verbosity}; +use pretty_assertions::assert_eq; + +use crate::{ + parser::ast::Module, + parser::{ParseError, Parser}, +}; + +struct SplitEmitter { + capture: miden_diagnostics::CaptureEmitter, + default: miden_diagnostics::DefaultEmitter, +} +impl SplitEmitter { + #[inline] + pub fn new() -> Self { + use miden_diagnostics::term::termcolor::ColorChoice; + + Self { + capture: Default::default(), + default: miden_diagnostics::DefaultEmitter::new(ColorChoice::Auto), + } + } + + #[allow(unused)] + pub fn captured(&self) -> String { + self.capture.captured() + } +} +impl Emitter for SplitEmitter { + #[inline] + fn buffer(&self) -> miden_diagnostics::term::termcolor::Buffer { + self.capture.buffer() + } + + #[inline] + fn print(&self, buffer: miden_diagnostics::term::termcolor::Buffer) -> std::io::Result<()> { + use std::io::Write; + + let mut copy = self.capture.buffer(); + copy.write_all(buffer.as_slice())?; + self.capture.print(buffer)?; + self.default.print(copy) + } +} + +// TEST HANDLER +// ================================================================================================ + +/// [ParseTest] is a container for the data required to run parser tests. Used to build an AST from +/// the given source string and asserts that executing the test will result in the expected AST. +/// +/// # Errors: +/// - ScanError test: check that the source provided contains valid characters and keywords. +/// - ParseError test: check that the parsed values are valid. +/// * InvalidInt: This error is returned if the parsed number is not a valid u64. +pub struct ParseTest { + pub diagnostics: Arc, + #[allow(unused)] + emitter: Arc, + parser: Parser, +} + +impl ParseTest { + // CONSTRUCTOR + // -------------------------------------------------------------------------------------------- + + /// Creates a new test, from the source string. + pub fn new() -> Self { + let codemap = Arc::new(CodeMap::new()); + let emitter = Arc::new(SplitEmitter::new()); + let config = DiagnosticsConfig { + verbosity: Verbosity::Warning, + warnings_as_errors: true, + no_warn: false, + display: Default::default(), + }; + let diagnostics = Arc::new(DiagnosticsHandler::new( + config, + codemap.clone(), + emitter.clone(), + )); + let parser = Parser::new((), codemap); + Self { + diagnostics, + emitter, + parser, + } + } + + /// This adds a new in-memory file to the [CodeMap] for this test. + /// + /// This is used when we want to write a test with imports, without having to place files on disk + #[allow(unused)] + pub fn add_virtual_file>(&self, name: P, content: String) { + self.parser.codemap.add(name.as_ref(), content); + } + + pub fn parse_module_from_file(&self, path: &str) -> Result { + self.parser + .parse_file::(&self.diagnostics, path) + } + + #[allow(unused)] + pub fn parse_module(&self, source: &str) -> Result { + self.parser + .parse_string::(&self.diagnostics, source) + } + + // TEST METHODS + // -------------------------------------------------------------------------------------------- + + #[track_caller] + #[allow(unused)] + pub fn expect_module_diagnostic(&self, source: &str, expected: &str) { + if let Err(err) = self.parse_module(source) { + self.diagnostics.emit(err); + assert!( + self.emitter.captured().contains(expected), + "expected diagnostic output to contain the string: '{}'", + expected + ); + } else { + panic!("expected parsing to fail, but it succeeded"); + } + } + + /// Parses a [Module] from the given source string and asserts that executing the test will result + /// in the expected AST. + #[track_caller] + #[allow(unused)] + pub fn expect_module_ast(&self, source: &str, expected: Module) { + match self.parse_module(source) { + Err(err) => { + self.diagnostics.emit(err); + panic!("expected parsing to succeed, see diagnostics for details"); + } + Ok(ast) => assert_eq!(ast, expected), + } + } + + /// Parses a [Module] from the given source path and asserts that executing the test will result + /// in the expected AST. + #[allow(unused)] + #[track_caller] + pub fn expect_module_ast_from_file(&self, path: &str, expected: Module) { + match self.parse_module_from_file(path) { + Err(err) => { + self.diagnostics.emit(err); + panic!("expected parsing to succeed, see diagnostics for details"); + } + Ok(ast) => assert_eq!(ast, expected), + } + } +} From af3adc15b13279904b5357e5c237253a456d6fca Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Tue, 24 Oct 2023 23:11:06 +0200 Subject: [PATCH 11/12] Updated dlmalloc expected output --- frontend-wasm/tests/expected/dlmalloc.mir | 1180 +++++++++++++++++++-- 1 file changed, 1108 insertions(+), 72 deletions(-) diff --git a/frontend-wasm/tests/expected/dlmalloc.mir b/frontend-wasm/tests/expected/dlmalloc.mir index 042965f73..c131e8485 100644 --- a/frontend-wasm/tests/expected/dlmalloc.mir +++ b/frontend-wasm/tests/expected/dlmalloc.mir @@ -6,16 +6,21 @@ global external gv2 : i32 = 0x001001d0 { id = gvar2 }; pub fn dlmalloc::dlmalloc::Dlmalloc::dispose_chunk(i32, i32, i32) { block0(v0: i32, v1: i32, v2: i32): +{ v3 = const.i32 0 : i32 v4 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v1, v2) : i32 v5 = call noname::dlmalloc::dlmalloc::Chunk::pinuse(v1) : i32 v6 = neq v5, 0 : i1 condbr v6, block4(v1, v2), block5 +} block1: - ret +{ + ret +} block2(v205: i32, v212: i32, v213: i32): +{ v206 = const.i32 256 : i32 v207 = cast v205 : u32 v208 = cast v206 : u32 @@ -23,26 +28,34 @@ block2(v205: i32, v212: i32, v213: i32): v210 = cast v209 : i32 v211 = neq v210, 0 : i1 condbr v211, block29, block30 +} block3: - ret +{ + ret +} block4(v93: i32, v94: i32): +{ v89 = call noname::dlmalloc::dlmalloc::Chunk::cinuse(v4) : i32 v90 = eq v89, 0 : i1 v91 = cast v90 : i32 v92 = neq v91, 0 : i1 condbr v92, block16, block17 +} block5: +{ v7 = cast v1 : u32 v8 = inttoptr v7 : *mut i32 v9 = load v8 : i32 v10 = call noname::dlmalloc::dlmalloc::Chunk::mmapped(v1) : i32 v11 = neq v10, 0 : i1 condbr v11, block6, block7 +} block6: +{ v72 = sub v1, v9 : i32 v73 = add v2, v9 : i32 v74 = const.i32 16 : i32 @@ -52,8 +65,10 @@ block6: v78 = cast v77 : i32 v79 = neq v78, 0 : i1 condbr v79, block3, block15 +} block7: +{ v12 = add v9, v2 : i32 v13 = call noname::dlmalloc::dlmalloc::Chunk::minus_offset(v1, v9) : i32 v14 = cast v0 : u32 @@ -64,8 +79,10 @@ block7: v19 = cast v18 : i32 v20 = neq v19, 0 : i1 condbr v20, block8, block9 +} block8: +{ v34 = const.i32 256 : i32 v35 = cast v9 : u32 v36 = cast v34 : u32 @@ -73,8 +90,10 @@ block8: v38 = cast v37 : i32 v39 = neq v38, 0 : i1 condbr v39, block11, block12 +} block9: +{ v21 = cast v4 : u32 v22 = add v21, 4 : u32 v23 = inttoptr v22 : *mut i32 @@ -86,16 +105,20 @@ block9: v29 = cast v28 : i32 v30 = neq v29, 0 : i1 condbr v30, block4(v13, v12), block10 +} block10: +{ v31 = cast v0 : u32 v32 = add v31, 416 : u32 v33 = inttoptr v32 : *mut i32 store v33, v12 call noname::dlmalloc::dlmalloc::Chunk::set_free_with_pinuse(v13, v12, v4) - ret + ret +} block11: +{ v40 = cast v13 : u32 v41 = add v40, 12 : u32 v42 = inttoptr v41 : *mut i32 @@ -108,12 +131,16 @@ block11: v49 = cast v48 : i32 v50 = neq v49, 0 : i1 condbr v50, block13, block14 +} block12: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(v0, v13) br block4(v13, v12) +} block13: +{ v57 = cast v0 : u32 v58 = add v57, 408 : u32 v59 = inttoptr v58 : *mut i32 @@ -131,8 +158,10 @@ block13: v71 = inttoptr v70 : *mut i32 store v71, v68 br block4(v13, v12) +} block14: +{ v51 = cast v47 : u32 v52 = add v51, 12 : u32 v53 = inttoptr v52 : *mut i32 @@ -142,8 +171,10 @@ block14: v56 = inttoptr v55 : *mut i32 store v56, v47 br block4(v13, v12) +} block15: +{ v80 = cast v0 : u32 v81 = add v80, 432 : u32 v82 = inttoptr v81 : *mut i32 @@ -153,9 +184,11 @@ block15: v86 = add v85, 432 : u32 v87 = inttoptr v86 : *mut i32 store v87, v84 - ret + ret +} block16: +{ v96 = cast v0 : u32 v97 = add v96, 428 : u32 v98 = inttoptr v97 : *mut i32 @@ -164,12 +197,16 @@ block16: v101 = cast v100 : i32 v102 = neq v101, 0 : i1 condbr v102, block19, block20 +} block17: +{ call noname::dlmalloc::dlmalloc::Chunk::set_free_with_pinuse(v93, v94, v88) br block2(v94, v95, v93) +} block18: +{ v194 = cast v95 : u32 v195 = add v194, 424 : u32 v196 = inttoptr v195 : *mut i32 @@ -184,9 +221,11 @@ block18: v204 = inttoptr v203 : *mut i32 store v204, v201 call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk(v93, v201) - ret + ret +} block19: +{ v163 = cast v95 : u32 v164 = add v163, 428 : u32 v165 = inttoptr v164 : *mut i32 @@ -214,8 +253,10 @@ block19: v184 = cast v183 : i32 v185 = neq v184, 0 : i1 condbr v185, block3, block28 +} block20: +{ v103 = cast v95 : u32 v104 = add v103, 424 : u32 v105 = inttoptr v104 : *mut i32 @@ -224,8 +265,10 @@ block20: v108 = cast v107 : i32 v109 = neq v108, 0 : i1 condbr v109, block18, block21 +} block21: +{ v110 = call noname::dlmalloc::dlmalloc::Chunk::size(v88) : i32 v111 = add v110, v94 : i32 v112 = const.i32 256 : i32 @@ -235,8 +278,10 @@ block21: v116 = cast v115 : i32 v117 = neq v116, 0 : i1 condbr v117, block23, block24 +} block22: +{ call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk(v93, v111) v153 = cast v95 : u32 v154 = add v153, 424 : u32 @@ -246,8 +291,10 @@ block22: v158 = cast v157 : i32 v159 = neq v158, 0 : i1 condbr v159, block2(v151, v152, v150), block27 +} block23: +{ v118 = cast v88 : u32 v119 = add v118, 12 : u32 v120 = inttoptr v119 : *mut i32 @@ -260,12 +307,16 @@ block23: v127 = cast v126 : i32 v128 = neq v127, 0 : i1 condbr v128, block25, block26 +} block24: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(v95, v88) br block22 +} block25: +{ v135 = cast v95 : u32 v136 = add v135, 408 : u32 v137 = inttoptr v136 : *mut i32 @@ -283,8 +334,10 @@ block25: v149 = inttoptr v148 : *mut i32 store v149, v146 br block22 +} block26: +{ v129 = cast v125 : u32 v130 = add v129, 12 : u32 v131 = inttoptr v130 : *mut i32 @@ -294,15 +347,19 @@ block26: v134 = inttoptr v133 : *mut i32 store v134, v125 br block22 +} block27: +{ v160 = cast v152 : u32 v161 = add v160, 416 : u32 v162 = inttoptr v161 : *mut i32 store v162, v151 br block3 +} block28: +{ v186 = const.i32 0 : i32 v187 = cast v95 : u32 v188 = add v187, 416 : u32 @@ -313,9 +370,11 @@ block28: v192 = add v191, 424 : u32 v193 = inttoptr v192 : *mut i32 store v193, v190 - ret + ret +} block29: +{ v214 = const.i32 -8 : i32 v215 = band v205, v214 : i32 v216 = add v212, v215 : i32 @@ -337,12 +396,16 @@ block29: v232 = cast v231 : i32 v233 = neq v232, 0 : i1 condbr v233, block32, block33 +} block30: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk(v212, v213, v205) - ret + ret +} block31(v247: i32): +{ v244 = cast v218 : u32 v245 = add v244, 8 : u32 v246 = inttoptr v245 : *mut i32 @@ -360,25 +423,31 @@ block31(v247: i32): v256 = inttoptr v255 : *mut i32 store v256, v247 br block1 +} block32: +{ v238 = bor v222, v229 : i32 v239 = cast v212 : u32 v240 = add v239, 408 : u32 v241 = inttoptr v240 : *mut i32 store v241, v238 br block31(v218) +} block33: +{ v234 = cast v218 : u32 v235 = add v234, 8 : u32 v236 = inttoptr v235 : *mut i32 v237 = load v236 : i32 br block31(v237) } +} pub fn dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(i32, i32) { block0(v0: i32, v1: i32): +{ v2 = const.i32 0 : i32 v3 = cast v1 : u32 v4 = add v3, 24 : u32 @@ -389,24 +458,32 @@ block0(v0: i32, v1: i32): v9 = cast v8 : i32 v10 = neq v9, 0 : i1 condbr v10, block4, block5 +} block1: - ret +{ + ret +} block2(v96: i32): +{ v65 = eq v6, 0 : i1 v66 = cast v65 : i32 v67 = neq v66, 0 : i1 condbr v67, block10, block11 +} block3: +{ v36 = const.i32 16 : i32 v37 = add v1, v36 : i32 v38 = neq v17, 0 : i1 v39 = select v38, v14, v37 : i32 br block7(v39, v23) +} block4: +{ v26 = call noname::dlmalloc::dlmalloc::TreeChunk::prev(v1) : i32 v27 = call noname::dlmalloc::dlmalloc::TreeChunk::next(v1) : i32 v28 = call noname::dlmalloc::dlmalloc::TreeChunk::chunk(v27) : i32 @@ -420,8 +497,10 @@ block4: v35 = inttoptr v34 : *mut i32 store v35, v32 br block2(v27) +} block5: +{ v11 = const.i32 20 : i32 v12 = const.i32 16 : i32 v13 = const.i32 20 : i32 @@ -437,12 +516,16 @@ block5: v23 = load v22 : i32 v24 = neq v23, 0 : i1 condbr v24, block3, block6 +} block6: +{ v25 = const.i32 0 : i32 br block2(v25) +} block7(v40: i32, v41: i32): +{ v42 = const.i32 20 : i32 v43 = add v41, v42 : i32 v44 = const.i32 16 : i32 @@ -462,21 +545,29 @@ block7(v40: i32, v41: i32): v58 = load v57 : i32 v59 = neq v58, 0 : i1 condbr v59, block7(v50, v58), block9 +} block8: +{ v60 = const.i32 0 : i32 v61 = cast v40 : u32 v62 = inttoptr v61 : *mut i32 store v62, v60 br block2(v41) +} block9: +{ br block8 +} block10: +{ br block1 +} block11: +{ v72 = cast v1 : u32 v73 = add v72, 28 : u32 v74 = inttoptr v73 : *mut i32 @@ -491,8 +582,10 @@ block11: v83 = cast v82 : i32 v84 = neq v83, 0 : i1 condbr v84, block13, block14 +} block12: +{ v115 = cast v96 : u32 v116 = add v115, 24 : u32 v117 = inttoptr v116 : *mut i32 @@ -505,15 +598,19 @@ block12: v124 = cast v123 : i32 v125 = neq v124, 0 : i1 condbr v125, block17, block18 +} block13: +{ v100 = cast v78 : u32 v101 = inttoptr v100 : *mut i32 store v101, v96 v102 = neq v96, 0 : i1 condbr v102, block12, block16 +} block14: +{ v85 = const.i32 16 : i32 v86 = const.i32 20 : i32 v87 = cast v63 : u32 @@ -530,11 +627,15 @@ block14: store v98, v96 v99 = neq v96, 0 : i1 condbr v99, block12, block15 +} block15: +{ br block10 +} block16: +{ v103 = cast v68 : u32 v104 = add v103, 412 : u32 v105 = inttoptr v104 : *mut i32 @@ -546,9 +647,11 @@ block16: v111 = add v110, 412 : u32 v112 = inttoptr v111 : *mut i32 store v112, v109 - ret + ret +} block17: +{ v133 = const.i32 20 : i32 v134 = add v118, v133 : i32 v135 = cast v134 : u32 @@ -558,8 +661,10 @@ block17: v139 = cast v138 : i32 v140 = neq v139, 0 : i1 condbr v140, block10, block19 +} block18: +{ v126 = cast v113 : u32 v127 = add v126, 16 : u32 v128 = inttoptr v127 : *mut i32 @@ -569,8 +674,10 @@ block18: v131 = inttoptr v130 : *mut i32 store v131, v113 br block17 +} block19: +{ v142 = const.i32 20 : i32 v143 = add v113, v142 : i32 v144 = cast v143 : u32 @@ -580,11 +687,13 @@ block19: v147 = add v146, 24 : u32 v148 = inttoptr v147 : *mut i32 store v148, v141 - ret + ret +} } pub fn dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk(i32, i32, i32) { block0(v0: i32, v1: i32, v2: i32): +{ v3 = const.i32 0 : i32 v4 = const.i32 0 : i32 v5 = const.i32 256 : i32 @@ -594,11 +703,15 @@ block0(v0: i32, v1: i32, v2: i32): v9 = cast v8 : i32 v10 = neq v9, 0 : i1 condbr v10, block2(v4), block3 +} block1: - ret +{ + ret +} block2(v42: i32): +{ v38 = const.i64 0 : i64 v39 = cast v1 : u32 v40 = add v39, 16 : u32 @@ -623,8 +736,10 @@ block2(v42: i32): v59 = cast v58 : i32 v60 = neq v59, 0 : i1 condbr v60, block6, block7 +} block3: +{ v11 = const.i32 31 : i32 v12 = const.i32 16777215 : i32 v13 = cast v2 : u32 @@ -633,8 +748,10 @@ block3: v16 = cast v15 : i32 v17 = neq v16, 0 : i1 condbr v17, block2(v11), block4 +} block4: +{ v18 = const.i32 6 : i32 v19 = const.i32 8 : i32 v20 = cast v2 : u32 @@ -655,8 +772,10 @@ block4: v35 = const.i32 62 : i32 v36 = add v34, v35 : i32 br block2(v36) +} block5(v128: i32): +{ v129 = cast v128 : u32 v130 = add v129, 8 : u32 v131 = inttoptr v130 : *mut i32 @@ -666,8 +785,10 @@ block5(v128: i32): v134 = inttoptr v133 : *mut i32 store v134, v128 br block1 +} block6: +{ v119 = bor v54, v56 : i32 v120 = cast v46 : u32 v121 = add v120, 412 : u32 @@ -681,24 +802,30 @@ block6: v127 = inttoptr v126 : *mut i32 store v127, v37 br block5(v50) +} block7: +{ v61 = cast v49 : u32 v62 = inttoptr v61 : *mut i32 v63 = load v62 : i32 v65 = call noname::dlmalloc::dlmalloc::leftshift_for_tree_index(v42) : i32 v66 = shl v2, v65 : i32 br block8(v63, v66) +} block8(v67: i32, v97: i32): +{ v68 = call noname::dlmalloc::dlmalloc::TreeChunk::chunk(v67) : i32 v69 = call noname::dlmalloc::dlmalloc::Chunk::size(v68) : i32 v71 = neq v69, v70 : i1 v72 = cast v71 : i32 v73 = neq v72, 0 : i1 condbr v73, block10, block11 +} block9: +{ v114 = cast v109 : u32 v115 = inttoptr v114 : *mut i32 store v115, v92 @@ -707,8 +834,10 @@ block9: v118 = inttoptr v117 : *mut i32 store v118, v67 br block5(v79) +} block10: +{ v98 = const.i32 29 : i32 v99 = cast v97 : u32 v100 = cast v98 : u32 @@ -726,8 +855,10 @@ block10: v112 = load v111 : i32 v113 = neq v112, 0 : i1 condbr v113, block8(v112, v104), block12 +} block11: +{ v74 = call noname::dlmalloc::dlmalloc::TreeChunk::chunk(v67) : i32 v75 = cast v74 : u32 v76 = add v75, 8 : u32 @@ -754,14 +885,18 @@ block11: v95 = add v94, 24 : u32 v96 = inttoptr v95 : *mut i32 store v96, v93 - ret + ret +} block12: +{ br block9 } +} pub fn dlmalloc::dlmalloc::Dlmalloc::release_unused_segments(i32) -> i32 { block0(v0: i32): +{ v2 = const.i32 0 : i32 v3 = const.i32 136 : i32 v4 = add v0, v3 : i32 @@ -770,11 +905,15 @@ block0(v0: i32): v7 = load v6 : i32 v8 = neq v7, 0 : i1 condbr v8, block3, block4 +} block1(v1: i32): - ret v1 +{ + ret (v1) +} block2(v126: i32, v127: i32, v139: i32): +{ v128 = const.i32 4095 : i32 v129 = const.i32 4095 : i32 v130 = cast v127 : u32 @@ -788,20 +927,26 @@ block2(v126: i32, v127: i32, v139: i32): v138 = inttoptr v137 : *mut i32 store v138, v135 br block1(v139) +} block3: +{ v11 = const.i32 128 : i32 v12 = add v0, v11 : i32 v13 = const.i32 0 : i32 v14 = const.i32 0 : i32 br block5(v7, v0, v12, v13, v14) +} block4: +{ v9 = const.i32 0 : i32 v10 = const.i32 0 : i32 br block2(v0, v9, v10) +} block5(v15: i32, v27: i32, v102: i32, v108: i32, v114: i32): +{ v16 = cast v15 : u32 v17 = add v16, 8 : u32 v18 = inttoptr v17 : *mut i32 @@ -827,25 +972,35 @@ block5(v15: i32, v27: i32, v102: i32, v108: i32, v114: i32): v39 = cast v38 : i32 v40 = neq v39, 0 : i1 condbr v40, block8(v114, v19, v27, v108), block9 +} block6: +{ br block2(v121, v117, v124) +} block7(v112: i32, v118: i32, v121: i32, v123: i32, v124: i32): +{ v116 = const.i32 1 : i32 v117 = add v112, v116 : i32 v120 = neq v118, 0 : i1 condbr v120, block5(v118, v121, v123, v124, v117), block18 +} block8(v115: i32, v119: i32, v122: i32, v125: i32): +{ br block7(v115, v119, v122, v15, v125) +} block9: +{ v41 = call noname::dlmalloc::dlmalloc::Segment::is_extern(v15) : i32 v42 = neq v41, 0 : i1 condbr v42, block8(v114, v19, v27, v108), block10 +} block10: +{ v43 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v26) : i32 v44 = const.i32 8 : i32 v45 = call noname::dlmalloc::dlmalloc::align_up(v43, v44) : i32 @@ -864,8 +1019,10 @@ block10: v58 = call noname::dlmalloc::dlmalloc::Chunk::inuse(v47) : i32 v59 = neq v58, 0 : i1 condbr v59, block8(v114, v19, v27, v108), block11 +} block11: +{ v60 = add v47, v48 : i32 v61 = add v49, v23 : i32 v62 = add v51, v54 : i32 @@ -878,8 +1035,10 @@ block11: v69 = cast v68 : i32 v70 = neq v69, 0 : i1 condbr v70, block8(v114, v19, v27, v108), block12 +} block12: +{ v71 = cast v27 : u32 v72 = add v71, 424 : u32 v73 = inttoptr v72 : *mut i32 @@ -888,13 +1047,17 @@ block12: v76 = cast v75 : i32 v77 = neq v76, 0 : i1 condbr v77, block14, block15 +} block13: +{ v89 = call noname::::free(v27, v26, v23) : i32 v90 = neq v89, 0 : i1 condbr v90, block16, block17 +} block14: +{ v78 = const.i32 0 : i32 v79 = cast v27 : u32 v80 = add v79, 416 : u32 @@ -906,12 +1069,16 @@ block14: v85 = inttoptr v84 : *mut i32 store v85, v82 br block13 +} block15: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(v27, v47) br block13 +} block16: +{ v93 = cast v86 : u32 v94 = add v93, 432 : u32 v95 = inttoptr v94 : *mut i32 @@ -927,17 +1094,23 @@ block16: store v106, v19 v109 = add v88, v108 : i32 br block7(v114, v103, v86, v101, v109) +} block17: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk(v86, v47, v48) br block8(v113, v103, v86, v107) +} block18: +{ br block6 } +} pub fn dlmalloc::dlmalloc::Dlmalloc::free(i32, i32) { block0(v0: i32, v1: i32): +{ v2 = const.i32 0 : i32 v3 = call noname::dlmalloc::dlmalloc::Chunk::from_mem(v1) : i32 v4 = call noname::dlmalloc::dlmalloc::Chunk::size(v3) : i32 @@ -945,29 +1118,39 @@ block0(v0: i32, v1: i32): v6 = call noname::dlmalloc::dlmalloc::Chunk::pinuse(v3) : i32 v7 = neq v6, 0 : i1 condbr v7, block3(v3, v4), block4 +} block1: - ret +{ + ret +} block2: +{ br block1 +} block3(v94: i32, v95: i32): +{ v90 = call noname::dlmalloc::dlmalloc::Chunk::cinuse(v5) : i32 v91 = eq v90, 0 : i1 v92 = cast v91 : i32 v93 = neq v92, 0 : i1 condbr v93, block16, block17 +} block4: +{ v8 = cast v3 : u32 v9 = inttoptr v8 : *mut i32 v10 = load v9 : i32 v11 = call noname::dlmalloc::dlmalloc::Chunk::mmapped(v3) : i32 v12 = neq v11, 0 : i1 condbr v12, block5, block6 +} block5: +{ v73 = sub v3, v10 : i32 v74 = add v4, v10 : i32 v75 = const.i32 16 : i32 @@ -977,8 +1160,10 @@ block5: v79 = cast v78 : i32 v80 = neq v79, 0 : i1 condbr v80, block2, block14 +} block6: +{ v13 = add v10, v4 : i32 v14 = call noname::dlmalloc::dlmalloc::Chunk::minus_offset(v3, v10) : i32 v15 = cast v0 : u32 @@ -989,8 +1174,10 @@ block6: v20 = cast v19 : i32 v21 = neq v20, 0 : i1 condbr v21, block7, block8 +} block7: +{ v35 = const.i32 256 : i32 v36 = cast v10 : u32 v37 = cast v35 : u32 @@ -998,8 +1185,10 @@ block7: v39 = cast v38 : i32 v40 = neq v39, 0 : i1 condbr v40, block10, block11 +} block8: +{ v22 = cast v5 : u32 v23 = add v22, 4 : u32 v24 = inttoptr v23 : *mut i32 @@ -1011,16 +1200,20 @@ block8: v30 = cast v29 : i32 v31 = neq v30, 0 : i1 condbr v31, block3(v14, v13), block9 +} block9: +{ v32 = cast v0 : u32 v33 = add v32, 416 : u32 v34 = inttoptr v33 : *mut i32 store v34, v13 call noname::dlmalloc::dlmalloc::Chunk::set_free_with_pinuse(v14, v13, v5) - ret + ret +} block10: +{ v41 = cast v14 : u32 v42 = add v41, 12 : u32 v43 = inttoptr v42 : *mut i32 @@ -1033,12 +1226,16 @@ block10: v50 = cast v49 : i32 v51 = neq v50, 0 : i1 condbr v51, block12, block13 +} block11: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(v0, v14) br block3(v14, v13) +} block12: +{ v58 = cast v0 : u32 v59 = add v58, 408 : u32 v60 = inttoptr v59 : *mut i32 @@ -1056,8 +1253,10 @@ block12: v72 = inttoptr v71 : *mut i32 store v72, v69 br block3(v14, v13) +} block13: +{ v52 = cast v48 : u32 v53 = add v52, 12 : u32 v54 = inttoptr v53 : *mut i32 @@ -1067,8 +1266,10 @@ block13: v57 = inttoptr v56 : *mut i32 store v57, v48 br block3(v14, v13) +} block14: +{ v81 = cast v0 : u32 v82 = add v81, 432 : u32 v83 = inttoptr v82 : *mut i32 @@ -1078,9 +1279,11 @@ block14: v87 = add v86, 432 : u32 v88 = inttoptr v87 : *mut i32 store v88, v85 - ret + ret +} block15(v474: i32, v481: i32, v482: i32): +{ v475 = const.i32 256 : i32 v476 = cast v474 : u32 v477 = cast v475 : u32 @@ -1088,8 +1291,10 @@ block15(v474: i32, v481: i32, v482: i32): v479 = cast v478 : i32 v480 = neq v479, 0 : i1 condbr v480, block55, block56 +} block16: +{ v97 = cast v0 : u32 v98 = add v97, 428 : u32 v99 = inttoptr v98 : *mut i32 @@ -1098,12 +1303,16 @@ block16: v102 = cast v101 : i32 v103 = neq v102, 0 : i1 condbr v103, block21, block22 +} block17: +{ call noname::dlmalloc::dlmalloc::Chunk::set_free_with_pinuse(v94, v95, v89) br block15(v95, v96, v94) +} block18: +{ v208 = cast v96 : u32 v209 = add v208, 440 : u32 v210 = inttoptr v209 : *mut i32 @@ -1114,8 +1323,10 @@ block18: v215 = cast v214 : i32 v216 = neq v215, 0 : i1 condbr v216, block2, block31 +} block19: +{ v198 = const.i32 0 : i32 v199 = cast v96 : u32 v200 = add v199, 416 : u32 @@ -1127,8 +1338,10 @@ block19: v205 = inttoptr v204 : *mut i32 store v205, v202 br block18 +} block20: +{ v187 = cast v96 : u32 v188 = add v187, 424 : u32 v189 = inttoptr v188 : *mut i32 @@ -1143,9 +1356,11 @@ block20: v197 = inttoptr v196 : *mut i32 store v197, v194 call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk(v94, v194) - ret + ret +} block21: +{ v164 = cast v96 : u32 v165 = add v164, 428 : u32 v166 = inttoptr v165 : *mut i32 @@ -1173,8 +1388,10 @@ block21: v185 = cast v184 : i32 v186 = neq v185, 0 : i1 condbr v186, block19, block30 +} block22: +{ v104 = cast v96 : u32 v105 = add v104, 424 : u32 v106 = inttoptr v105 : *mut i32 @@ -1183,8 +1400,10 @@ block22: v109 = cast v108 : i32 v110 = neq v109, 0 : i1 condbr v110, block20, block23 +} block23: +{ v111 = call noname::dlmalloc::dlmalloc::Chunk::size(v89) : i32 v112 = add v111, v95 : i32 v113 = const.i32 256 : i32 @@ -1194,8 +1413,10 @@ block23: v117 = cast v116 : i32 v118 = neq v117, 0 : i1 condbr v118, block25, block26 +} block24: +{ call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk(v94, v112) v154 = cast v96 : u32 v155 = add v154, 424 : u32 @@ -1205,8 +1426,10 @@ block24: v159 = cast v158 : i32 v160 = neq v159, 0 : i1 condbr v160, block15(v152, v153, v151), block29 +} block25: +{ v119 = cast v89 : u32 v120 = add v119, 12 : u32 v121 = inttoptr v120 : *mut i32 @@ -1219,12 +1442,16 @@ block25: v128 = cast v127 : i32 v129 = neq v128, 0 : i1 condbr v129, block27, block28 +} block26: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(v96, v89) br block24 +} block27: +{ v136 = cast v96 : u32 v137 = add v136, 408 : u32 v138 = inttoptr v137 : *mut i32 @@ -1242,8 +1469,10 @@ block27: v150 = inttoptr v149 : *mut i32 store v150, v147 br block24 +} block28: +{ v130 = cast v126 : u32 v131 = add v130, 12 : u32 v132 = inttoptr v131 : *mut i32 @@ -1253,18 +1482,24 @@ block28: v135 = inttoptr v134 : *mut i32 store v135, v126 br block24 +} block29: +{ v161 = cast v153 : u32 v162 = add v161, 416 : u32 v163 = inttoptr v162 : *mut i32 store v163, v152 - ret + ret +} block30: +{ br block18 +} block31: +{ v217 = call noname::dlmalloc::dlmalloc::Chunk::mem_offset() : i32 v218 = const.i32 8 : i32 v219 = call noname::dlmalloc::dlmalloc::align_up(v217, v218) : i32 @@ -1300,8 +1535,10 @@ block31: v249 = cast v248 : i32 v250 = neq v249, 0 : i1 condbr v250, block2, block32 +} block32: +{ v251 = cast v207 : u32 v252 = add v251, 428 : u32 v253 = inttoptr v252 : *mut i32 @@ -1310,8 +1547,10 @@ block32: v256 = cast v255 : i32 v257 = neq v256, 0 : i1 condbr v257, block2, block33 +} block33: +{ v258 = call noname::dlmalloc::dlmalloc::Chunk::mem_offset() : i32 v259 = const.i32 8 : i32 v260 = call noname::dlmalloc::dlmalloc::align_up(v258, v259) : i32 @@ -1335,8 +1574,10 @@ block33: v278 = cast v277 : i32 v279 = neq v278, 0 : i1 condbr v279, block34(v207, v267), block35 +} block34(v449: i32, v452: i32): +{ v450 = call noname::dlmalloc::dlmalloc::Dlmalloc::release_unused_segments(v449) : i32 v451 = const.i32 0 : i32 v453 = sub v451, v452 : i32 @@ -1344,8 +1585,10 @@ block34(v449: i32, v452: i32): v455 = cast v454 : i32 v456 = neq v455, 0 : i1 condbr v456, block2, block53 +} block35: +{ v280 = sub v271, v274 : i32 v281 = const.i32 65535 : i32 v282 = add v280, v281 : i32 @@ -1356,14 +1599,18 @@ block35: v287 = const.i32 128 : i32 v288 = add v207, v287 : i32 br block37(v288) +} block36(v314: i32, v318: i32, v339: i32, v359: i32, v414: i32): +{ v313 = const.i32 0 : i32 v315 = call noname::dlmalloc::dlmalloc::Segment::is_extern(v314) : i32 v316 = neq v315, 0 : i1 condbr v316, block34(v318, v313), block43 +} block37(v289: i32): +{ v290 = cast v289 : u32 v291 = inttoptr v290 : *mut i32 v292 = load v291 : i32 @@ -1373,20 +1620,26 @@ block37(v289: i32): v297 = cast v296 : i32 v298 = neq v297, 0 : i1 condbr v298, block39, block40 +} block38: +{ v312 = const.i32 0 : i32 br block36(v312, v320, v341, v361, v416) +} block39: +{ v306 = cast v289 : u32 v307 = add v306, 8 : u32 v308 = inttoptr v307 : *mut i32 v309 = load v308 : i32 v310 = neq v309, 0 : i1 condbr v310, block37(v309), block42 +} block40: +{ v299 = call noname::dlmalloc::dlmalloc::Segment::top(v289) : i32 v300 = cast v299 : u32 v301 = cast v293 : u32 @@ -1394,14 +1647,20 @@ block40: v303 = cast v302 : i32 v304 = neq v303, 0 : i1 condbr v304, block36(v289, v207, v286, v288, v284), block41 +} block41: +{ br block39 +} block42: +{ br block38 +} block43: +{ v317 = const.i32 0 : i32 v321 = cast v314 : u32 v322 = add v321, 12 : u32 @@ -1417,8 +1676,10 @@ block43: v332 = cast v331 : i32 v333 = neq v332, 0 : i1 condbr v333, block34(v318, v317), block44 +} block44: +{ v334 = const.i32 0 : i32 v335 = cast v314 : u32 v336 = add v335, 4 : u32 @@ -1430,18 +1691,24 @@ block44: v345 = cast v344 : i32 v346 = neq v345, 0 : i1 condbr v346, block34(v318, v334), block45 +} block45: +{ br block46(v359) +} block46(v348: i32): +{ v349 = call noname::dlmalloc::dlmalloc::Segment::holds(v347, v348) : i32 v350 = eq v349, 0 : i1 v351 = cast v350 : i32 v352 = neq v351, 0 : i1 condbr v352, block48, block49 +} block47: +{ v363 = cast v347 : u32 v364 = inttoptr v363 : *mut i32 v365 = load v364 : i32 @@ -1456,30 +1723,40 @@ block47: v375 = cast v374 : i32 v376 = neq v375, 0 : i1 condbr v376, block34(v362, v373), block51 +} block48: +{ v354 = cast v348 : u32 v355 = add v354, 8 : u32 v356 = inttoptr v355 : *mut i32 v357 = load v356 : i32 v358 = neq v357, 0 : i1 condbr v358, block46(v357), block50 +} block49: +{ v353 = const.i32 0 : i32 br block34(v362, v353) +} block50: +{ br block47 +} block51: +{ v377 = const.i32 0 : i32 v378 = eq v372, 0 : i1 v379 = cast v378 : i32 v380 = neq v379, 0 : i1 condbr v380, block34(v362, v377), block52 +} block52: +{ v381 = cast v347 : u32 v382 = add v381, 4 : u32 v383 = inttoptr v382 : *mut i32 @@ -1552,8 +1829,10 @@ block52: v448 = inttoptr v447 : *mut i32 store v448, v445 br block34(v362, v370) +} block53: +{ v457 = cast v449 : u32 v458 = add v457, 420 : u32 v459 = inttoptr v458 : *mut i32 @@ -1568,16 +1847,20 @@ block53: v468 = cast v467 : i32 v469 = neq v468, 0 : i1 condbr v469, block2, block54 +} block54: +{ v470 = const.i32 -1 : i32 v471 = cast v449 : u32 v472 = add v471, 440 : u32 v473 = inttoptr v472 : *mut i32 store v473, v470 - ret + ret +} block55: +{ v494 = const.i32 -8 : i32 v495 = band v474, v494 : i32 v496 = add v481, v495 : i32 @@ -1599,8 +1882,10 @@ block55: v512 = cast v511 : i32 v513 = neq v512, 0 : i1 condbr v513, block59, block60 +} block56: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk(v481, v482, v474) v483 = cast v481 : u32 v484 = add v483, 448 : u32 @@ -1614,12 +1899,16 @@ block56: store v491, v488 v492 = neq v488, 0 : i1 condbr v492, block2, block57 +} block57: +{ v493 = call noname::dlmalloc::dlmalloc::Dlmalloc::release_unused_segments(v481) : i32 - ret + ret +} block58(v527: i32): +{ v524 = cast v498 : u32 v525 = add v524, 8 : u32 v526 = inttoptr v525 : *mut i32 @@ -1637,25 +1926,31 @@ block58(v527: i32): v536 = inttoptr v535 : *mut i32 store v536, v527 br block2 +} block59: +{ v518 = bor v502, v509 : i32 v519 = cast v481 : u32 v520 = add v519, 408 : u32 v521 = inttoptr v520 : *mut i32 store v521, v518 br block58(v498) +} block60: +{ v514 = cast v498 : u32 v515 = add v514, 8 : u32 v516 = inttoptr v515 : *mut i32 v517 = load v516 : i32 br block58(v517) } +} pub fn dlmalloc::dlmalloc::Dlmalloc::malloc(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = const.i32 0 : i32 v4 = const.i64 0 : i64 v5 = global.load (@__stack_pointer) as *mut i8 : i32 @@ -1670,18 +1965,24 @@ block0(v0: i32, v1: i32): v13 = cast v12 : i32 v14 = neq v13, 0 : i1 condbr v14, block7, block8 +} block1(v2: i32): - ret v2 +{ + ret (v2) +} block2(v1477: i32, v1501: i32): +{ v1498 = const.i32 16 : i32 v1499 = add v1477, v1498 : i32 v1500 = global.symbol @__stack_pointer : *mut i32 store v1500, v1499 br block1(v1501) +} block3(v654: i32, v662: i32, v682: i32): +{ v658 = cast v654 : u32 v659 = add v658, 416 : u32 v660 = inttoptr v659 : *mut i32 @@ -1692,22 +1993,30 @@ block3(v654: i32, v662: i32, v682: i32): v671 = cast v670 : i32 v672 = neq v671, 0 : i1 condbr v672, block83, block84 +} block4(v561: i32, v565: i32, v573: i32, v579: i32, v692: i32): +{ v562 = eq v561, 0 : i1 v563 = cast v562 : i32 v564 = neq v563, 0 : i1 condbr v564, block3(v565, v573, v692), block63 +} block5(v552: i32, v553: i32, v555: i32, v558: i32, v568: i32, v695: i32): +{ br block60(v552, v553, v558) +} block6(v493: i32, v495: i32, v501: i32, v506: i32, v514: i32, v557: i32, v560: i32, v688: i32): +{ v498 = bor v493, v495 : i32 v499 = neq v498, 0 : i1 condbr v499, block56(v493, v495), block57 +} block7: +{ v168 = const.i32 16 : i32 v169 = const.i32 4 : i32 v170 = add v1, v169 : i32 @@ -1743,8 +2052,10 @@ block7: v200 = cast v199 : i32 v201 = neq v200, 0 : i1 condbr v201, block23, block24 +} block8: +{ v15 = call noname::dlmalloc::dlmalloc::Chunk::mem_offset() : i32 v16 = const.i32 8 : i32 v17 = call noname::dlmalloc::dlmalloc::align_up(v15, v16) : i32 @@ -1783,8 +2094,10 @@ block8: v50 = cast v49 : i32 v51 = neq v50, 0 : i1 condbr v51, block2(v7, v24), block9 +} block9: +{ v52 = const.i32 4 : i32 v53 = add v1, v52 : i32 v54 = const.i32 8 : i32 @@ -1797,8 +2110,10 @@ block9: v61 = cast v60 : i32 v62 = neq v61, 0 : i1 condbr v62, block3(v0, v55, v7), block10 +} block10: +{ v63 = const.i32 0 : i32 v64 = const.i32 0 : i32 v65 = const.i32 256 : i32 @@ -1808,8 +2123,10 @@ block10: v69 = cast v68 : i32 v70 = neq v69, 0 : i1 condbr v70, block11(v64), block12 +} block11(v101: i32): +{ v97 = const.i32 0 : i32 v99 = sub v97, v55 : i32 v102 = const.i32 2 : i32 @@ -1820,8 +2137,10 @@ block11(v101: i32): v107 = load v106 : i32 v108 = neq v107, 0 : i1 condbr v108, block14, block15 +} block12: +{ v71 = const.i32 31 : i32 v72 = const.i32 16777215 : i32 v73 = cast v55 : u32 @@ -1830,8 +2149,10 @@ block12: v76 = cast v75 : i32 v77 = neq v76, 0 : i1 condbr v77, block11(v71), block13 +} block13: +{ v78 = const.i32 6 : i32 v79 = const.i32 8 : i32 v80 = cast v55 : u32 @@ -1852,19 +2173,25 @@ block13: v95 = const.i32 62 : i32 v96 = add v94, v95 : i32 br block11(v96) +} block14: +{ v110 = call noname::dlmalloc::dlmalloc::leftshift_for_tree_index(v101) : i32 v111 = shl v98, v110 : i32 v112 = const.i32 0 : i32 v113 = const.i32 0 : i32 br block16(v107, v99, v112, v111, v113, v101, v507, v100, v689) +} block15: +{ v109 = const.i32 0 : i32 br block6(v63, v109, v101, v59, v100, v98, v99, v7) +} block16(v114: i32, v124: i32, v139: i32, v141: i32, v497: i32, v503: i32, v509: i32, v516: i32, v691: i32): +{ v115 = call noname::dlmalloc::dlmalloc::TreeChunk::chunk(v114) : i32 v116 = call noname::dlmalloc::dlmalloc::Chunk::size(v115) : i32 v118 = cast v116 : u32 @@ -1873,10 +2200,14 @@ block16(v114: i32, v124: i32, v139: i32, v141: i32, v497: i32, v503: i32, v509: v121 = cast v120 : i32 v122 = neq v121, 0 : i1 condbr v122, block18(v124, v497), block19 +} block17: +{ +} block18(v167: i32, v496: i32): +{ v133 = const.i32 20 : i32 v134 = add v114, v133 : i32 v135 = cast v134 : u32 @@ -1907,8 +2238,10 @@ block18(v167: i32, v496: i32): v164 = cast v163 : i32 v165 = neq v164, 0 : i1 condbr v165, block6(v160, v496, v503, v509, v516, v166, v167, v691), block22 +} block19: +{ v123 = sub v116, v117 : i32 v125 = cast v123 : u32 v126 = cast v124 : u32 @@ -1916,19 +2249,27 @@ block19: v128 = cast v127 : i32 v129 = neq v128, 0 : i1 condbr v129, block18(v124, v497), block20 +} block20: +{ v130 = neq v123, 0 : i1 condbr v130, block18(v123, v114), block21 +} block21: +{ v131 = const.i32 0 : i32 br block5(v114, v114, v117, v131, v516, v691) +} block22: +{ br block16(v154, v167, v160, v162, v496, v502, v508, v515, v690) +} block23: +{ v241 = cast v0 : u32 v242 = add v241, 416 : u32 v243 = inttoptr v242 : *mut i32 @@ -1939,8 +2280,10 @@ block23: v248 = cast v247 : i32 v249 = neq v248, 0 : i1 condbr v249, block3(v0, v183, v7), block28 +} block24: +{ v202 = const.i32 -1 : i32 v203 = bxor v196, v202 : i32 v204 = const.i32 1 : i32 @@ -1964,15 +2307,19 @@ block24: v222 = cast v221 : i32 v223 = neq v222, 0 : i1 condbr v223, block26, block27 +} block25: +{ v238 = const.i32 3 : i32 v239 = shl v206, v238 : i32 call noname::dlmalloc::dlmalloc::Chunk::set_inuse_and_pinuse(v214, v239) v240 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v236) : i32 br block2(v7, v240) +} block26: +{ v230 = const.i32 -2 : i32 v231 = shl v230, v206 : i32 v232 = band v187, v231 : i32 @@ -1981,8 +2328,10 @@ block26: v235 = inttoptr v234 : *mut i32 store v235, v232 br block25 +} block27: +{ v224 = cast v218 : u32 v225 = add v224, 12 : u32 v226 = inttoptr v225 : *mut i32 @@ -1992,19 +2341,25 @@ block27: v229 = inttoptr v228 : *mut i32 store v229, v218 br block25 +} block28: +{ v250 = neq v196, 0 : i1 condbr v250, block35, block36 +} block29(v655: i32, v683: i32): +{ v489 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v291) : i32 v490 = eq v489, 0 : i1 v491 = cast v490 : i32 v492 = neq v491, 0 : i1 condbr v492, block3(v655, v292, v683), block55 +} block30: +{ v478 = cast v294 : u32 v479 = add v478, 424 : u32 v480 = inttoptr v479 : *mut i32 @@ -2014,8 +2369,10 @@ block30: v485 = inttoptr v484 : *mut i32 store v485, v296 br block29(v474, v684) +} block31(v1479: i32): +{ v463 = cast v359 : u32 v464 = add v463, 424 : u32 v465 = inttoptr v464 : *mut i32 @@ -2026,8 +2383,10 @@ block31(v1479: i32): store v470, v358 v473 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v352) : i32 br block2(v1479, v473) +} block32: +{ v414 = const.i32 -8 : i32 v415 = band v363, v414 : i32 v416 = add v312, v415 : i32 @@ -2051,13 +2410,17 @@ block32: v434 = cast v433 : i32 v435 = neq v434, 0 : i1 condbr v435, block53, block54 +} block33: +{ v412 = add v296, v292 : i32 call noname::dlmalloc::dlmalloc::Chunk::set_inuse_and_pinuse(v291, v412) br block29(v294, v7) +} block34: +{ v365 = const.i32 -8 : i32 v366 = band v309, v365 : i32 v367 = add v294, v366 : i32 @@ -2083,8 +2446,10 @@ block34: v387 = cast v386 : i32 v388 = neq v387, 0 : i1 condbr v388, block50, block51 +} block35: +{ v311 = const.i32 144 : i32 v312 = add v0, v311 : i32 v313 = const.i32 1 : i32 @@ -2111,8 +2476,10 @@ block35: v334 = cast v333 : i32 v335 = neq v334, 0 : i1 condbr v335, block46, block47 +} block36: +{ v251 = cast v0 : u32 v252 = add v251, 412 : u32 v253 = inttoptr v252 : *mut i32 @@ -2121,8 +2488,10 @@ block36: v256 = cast v255 : i32 v257 = neq v256, 0 : i1 condbr v257, block3(v0, v183, v7), block37 +} block37: +{ v258 = call noname::dlmalloc::dlmalloc::least_bit(v254) : i32 v259 = popcnt v258 : i32 v260 = const.i32 2 : i32 @@ -2139,8 +2508,10 @@ block37: v271 = cast v270 : i32 v272 = neq v271, 0 : i1 condbr v272, block38(v265, v183, v268), block39 +} block38(v290: i32, v292: i32, v296: i32): +{ v291 = call noname::dlmalloc::dlmalloc::TreeChunk::chunk(v290) : i32 v293 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v291, v292) : i32 call noname::dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(v0, v290) @@ -2153,11 +2524,15 @@ block38(v290: i32, v292: i32, v296: i32): v303 = cast v302 : i32 v304 = neq v303, 0 : i1 condbr v304, block33, block43 +} block39: +{ br block40(v269, v268, v265) +} block40(v273: i32, v278: i32, v285: i32): +{ v274 = call noname::dlmalloc::dlmalloc::TreeChunk::chunk(v273) : i32 v275 = call noname::dlmalloc::dlmalloc::Chunk::size(v274) : i32 v277 = sub v275, v276 : i32 @@ -2172,14 +2547,20 @@ block40(v273: i32, v278: i32, v285: i32): v288 = call noname::dlmalloc::dlmalloc::TreeChunk::leftmost_child(v273) : i32 v289 = neq v288, 0 : i1 condbr v289, block40(v288, v284, v287), block42 +} block41: +{ br block38(v287, v276, v284) +} block42: +{ br block41 +} block43: +{ v305 = call noname::dlmalloc::dlmalloc::TreeChunk::chunk(v293) : i32 call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk(v291, v292) call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk(v305, v296) @@ -2189,11 +2570,15 @@ block43: v309 = load v308 : i32 v310 = neq v309, 0 : i1 condbr v310, block34, block44 +} block44: +{ br block30 +} block45: +{ call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk(v328, v183) v354 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v352, v353) : i32 v356 = const.i32 3 : i32 @@ -2206,8 +2591,10 @@ block45: v363 = load v362 : i32 v364 = neq v363, 0 : i1 condbr v364, block32, block48 +} block46: +{ v342 = cast v0 : u32 v343 = add v342, 408 : u32 v344 = inttoptr v343 : *mut i32 @@ -2220,8 +2607,10 @@ block46: v351 = inttoptr v350 : *mut i32 store v351, v348 br block45 +} block47: +{ v336 = cast v332 : u32 v337 = add v336, 12 : u32 v338 = inttoptr v337 : *mut i32 @@ -2231,11 +2620,15 @@ block47: v341 = inttoptr v340 : *mut i32 store v341, v332 br block45 +} block48: +{ br block31(v7) +} block49(v402: i32): +{ v399 = cast v369 : u32 v400 = add v399, 8 : u32 v401 = inttoptr v400 : *mut i32 @@ -2253,23 +2646,29 @@ block49(v402: i32): v411 = inttoptr v410 : *mut i32 store v411, v402 br block30 +} block50: +{ v393 = bor v377, v384 : i32 v394 = cast v294 : u32 v395 = add v394, 408 : u32 v396 = inttoptr v395 : *mut i32 store v396, v393 br block49(v369) +} block51: +{ v389 = cast v369 : u32 v390 = add v389, 8 : u32 v391 = inttoptr v390 : *mut i32 v392 = load v391 : i32 br block49(v392) +} block52(v449: i32): +{ v446 = cast v416 : u32 v447 = add v446, 8 : u32 v448 = inttoptr v447 : *mut i32 @@ -2287,32 +2686,42 @@ block52(v449: i32): v458 = inttoptr v457 : *mut i32 store v458, v449 br block31(v1480) +} block53: +{ v440 = bor v424, v431 : i32 v441 = cast v359 : u32 v442 = add v441, 408 : u32 v443 = inttoptr v442 : *mut i32 store v443, v440 br block52(v416) +} block54: +{ v436 = cast v416 : u32 v437 = add v436, 8 : u32 v438 = inttoptr v437 : *mut i32 v439 = load v438 : i32 br block52(v439) +} block55: +{ br block2(v683, v489) +} block56(v526: i32, v554: i32): +{ v527 = eq v526, 0 : i1 v528 = cast v527 : i32 v529 = neq v528, 0 : i1 condbr v529, block4(v554, v514, v556, v559, v688), block59 +} block57: +{ v500 = const.i32 1 : i32 v504 = shl v500, v501 : i32 v505 = call noname::dlmalloc::dlmalloc::left_bits(v504) : i32 @@ -2321,8 +2730,10 @@ block57: v512 = cast v511 : i32 v513 = neq v512, 0 : i1 condbr v513, block3(v514, v557, v688), block58 +} block58: +{ v517 = call noname::dlmalloc::dlmalloc::least_bit(v510) : i32 v518 = popcnt v517 : i32 v519 = const.i32 2 : i32 @@ -2333,11 +2744,15 @@ block58: v524 = load v523 : i32 v525 = const.i32 0 : i32 br block56(v524, v525) +} block59: +{ br block5(v526, v554, v557, v560, v566, v693) +} block60(v530: i32, v531: i32, v540: i32): +{ v532 = call noname::dlmalloc::dlmalloc::TreeChunk::chunk(v530) : i32 v533 = call noname::dlmalloc::dlmalloc::Chunk::size(v532) : i32 v535 = cast v533 : u32 @@ -2357,14 +2772,20 @@ block60(v530: i32, v531: i32, v540: i32): v550 = call noname::dlmalloc::dlmalloc::TreeChunk::leftmost_child(v530) : i32 v551 = neq v550, 0 : i1 condbr v551, block60(v550, v547, v549), block62 +} block61: +{ br block4(v547, v568, v534, v549, v695) +} block62: +{ br block61 +} block63: +{ v569 = cast v565 : u32 v570 = add v569, 416 : u32 v571 = inttoptr v570 : *mut i32 @@ -2375,8 +2796,10 @@ block63: v577 = cast v576 : i32 v578 = neq v577, 0 : i1 condbr v578, block64, block65 +} block64: +{ v587 = call noname::dlmalloc::dlmalloc::TreeChunk::chunk(v561) : i32 v589 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v587, v573) : i32 call noname::dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(v565, v586) @@ -2389,8 +2812,10 @@ block64: v598 = cast v597 : i32 v599 = neq v598, 0 : i1 condbr v599, block68, block69 +} block65: +{ v580 = sub v572, v573 : i32 v581 = cast v579 : u32 v582 = cast v580 : u32 @@ -2398,21 +2823,29 @@ block65: v584 = cast v583 : i32 v585 = neq v584, 0 : i1 condbr v585, block3(v565, v573, v692), block66 +} block66: +{ br block64 +} block67(v696: i32): +{ v652 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v587) : i32 v653 = neq v652, 0 : i1 condbr v653, block2(v696, v652), block75 +} block68: +{ v649 = add v591, v588 : i32 call noname::dlmalloc::dlmalloc::Chunk::set_inuse_and_pinuse(v587, v649) br block67(v697) +} block69: +{ call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk(v587, v588) call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk(v589, v591) v600 = const.i32 256 : i32 @@ -2422,8 +2855,10 @@ block69: v604 = cast v603 : i32 v605 = neq v604, 0 : i1 condbr v605, block70, block71 +} block70: +{ v606 = const.i32 -8 : i32 v607 = band v591, v606 : i32 v608 = add v590, v607 : i32 @@ -2445,12 +2880,16 @@ block70: v624 = cast v623 : i32 v625 = neq v624, 0 : i1 condbr v625, block73, block74 +} block71: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk(v590, v589, v591) br block67(v692) +} block72(v639: i32): +{ v636 = cast v610 : u32 v637 = add v636, 8 : u32 v638 = inttoptr v637 : *mut i32 @@ -2468,26 +2907,34 @@ block72(v639: i32): v648 = inttoptr v647 : *mut i32 store v648, v639 br block67(v697) +} block73: +{ v630 = bor v614, v621 : i32 v631 = cast v590 : u32 v632 = add v631, 408 : u32 v633 = inttoptr v632 : *mut i32 store v633, v630 br block72(v610) +} block74: +{ v626 = cast v610 : u32 v627 = add v626, 8 : u32 v628 = inttoptr v627 : *mut i32 v629 = load v628 : i32 br block72(v629) +} block75: +{ br block3(v590, v588, v696) +} block76(v1438: i32, v1444: i32, v1488: i32, v1502: i32): +{ v1440 = cast v1438 : u32 v1441 = add v1440, 420 : u32 v1442 = inttoptr v1441 : *mut i32 @@ -2498,8 +2945,10 @@ block76(v1438: i32, v1444: i32, v1488: i32, v1502: i32): v1457 = cast v1456 : i32 v1458 = neq v1457, 0 : i1 condbr v1458, block2(v1488, v1502), block144 +} block77(v1321: i32, v1326: i32): +{ v1322 = const.i32 4095 : i32 v1323 = cast v1321 : u32 v1324 = add v1323, 448 : u32 @@ -2521,8 +2970,10 @@ block77(v1321: i32, v1326: i32): store v1341, v737 v1342 = const.i32 0 : i32 br block141(v1342) +} block78(v1263: i32, v1264: i32): +{ call noname::dlmalloc::dlmalloc::Chunk::set_free_with_pinuse(v1093, v1263, v1264) v1265 = const.i32 256 : i32 v1266 = cast v1263 : u32 @@ -2531,8 +2982,10 @@ block78(v1263: i32, v1264: i32): v1269 = cast v1268 : i32 v1270 = neq v1269, 0 : i1 condbr v1270, block136, block137 +} block79: +{ v1248 = const.i32 0 : i32 v1249 = cast v654 : u32 v1250 = add v1249, 424 : u32 @@ -2550,8 +3003,10 @@ block79: call noname::dlmalloc::dlmalloc::Chunk::set_inuse_and_pinuse(v1196, v1255) v1260 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v1196) : i32 br block2(v682, v1260) +} block80: +{ v1236 = cast v841 : u32 v1237 = add v1236, 424 : u32 v1238 = inttoptr v1237 : *mut i32 @@ -2568,8 +3023,10 @@ block80: call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk(v1093, v1243) v1247 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v1089) : i32 br block2(v1482, v1247) +} block81: +{ v1219 = cast v775 : u32 v1220 = add v1219, 4 : u32 v1221 = inttoptr v1220 : *mut i32 @@ -2590,15 +3047,19 @@ block81: v1235 = add v1234, v815 : i32 call noname::dlmalloc::dlmalloc::Dlmalloc::init_top(v792, v1230, v1235) br block76(v792, v1092, v1484, v1509) +} block82: +{ v1216 = cast v654 : u32 v1217 = add v1216, 444 : u32 v1218 = inttoptr v1217 : *mut i32 store v1218, v722 br block77(v1214, v1215) +} block83: +{ v1193 = cast v654 : u32 v1194 = add v1193, 424 : u32 v1195 = inttoptr v1194 : *mut i32 @@ -2613,8 +3074,10 @@ block83: v1204 = cast v1203 : i32 v1205 = neq v1204, 0 : i1 condbr v1205, block79, block135 +} block84: +{ v673 = cast v654 : u32 v674 = add v673, 420 : u32 v675 = inttoptr v674 : *mut i32 @@ -2625,8 +3088,10 @@ block84: v680 = cast v679 : i32 v681 = neq v680, 0 : i1 condbr v681, block85, block86 +} block85: +{ v1175 = sub v676, v662 : i32 v1176 = cast v654 : u32 v1177 = add v1176, 420 : u32 @@ -2650,8 +3115,10 @@ block85: call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk(v1182, v662) v1192 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v1182) : i32 br block2(v682, v1192) +} block86: +{ v699 = const.i32 4 : i32 v700 = add v682, v699 : i32 v701 = call noname::dlmalloc::dlmalloc::Chunk::mem_offset() : i32 @@ -2681,8 +3148,10 @@ block86: v724 = cast v723 : i32 v725 = neq v724, 0 : i1 condbr v725, block2(v682, v718), block87 +} block87: +{ v726 = cast v682 : u32 v727 = add v726, 12 : u32 v728 = inttoptr v727 : *mut i32 @@ -2720,13 +3189,17 @@ block87: v758 = load v757 : i32 v759 = neq v758, 0 : i1 condbr v759, block88, block89 +} block88: +{ v772 = const.i32 128 : i32 v773 = add v654, v772 : i32 br block94(v773) +} block89: +{ v760 = cast v654 : u32 v761 = add v760, 444 : u32 v762 = inttoptr v761 : *mut i32 @@ -2735,19 +3208,25 @@ block89: v765 = cast v764 : i32 v766 = neq v765, 0 : i1 condbr v766, block82, block90 +} block90: +{ v767 = cast v722 : u32 v768 = cast v763 : u32 v769 = lt v767, v768 : i1 v770 = cast v769 : i32 v771 = neq v770, 0 : i1 condbr v771, block82, block91 +} block91: +{ br block77(v654, v722) +} block92(v814: i32, v817: i32, v1091: i32, v1483: i32, v1508: i32): +{ v800 = cast v799 : u32 v801 = add v800, 444 : u32 v802 = inttoptr v801 : *mut i32 @@ -2764,40 +3243,54 @@ block92(v814: i32, v817: i32, v1091: i32, v1483: i32, v1508: i32): store v813, v810 v816 = add v804, v814 : i32 br block104(v817) +} block93: +{ v785 = call noname::dlmalloc::dlmalloc::Segment::is_extern(v775) : i32 v786 = neq v785, 0 : i1 condbr v786, block92(v815, v818, v1092, v1484, v1509), block98 +} block94(v775: i32): +{ v776 = call noname::dlmalloc::dlmalloc::Segment::top(v775) : i32 v777 = eq v774, v776 : i1 v778 = cast v777 : i32 v779 = neq v778, 0 : i1 condbr v779, block93, block96 +} block95: +{ +} block96: +{ v780 = cast v775 : u32 v781 = add v780, 8 : u32 v782 = inttoptr v781 : *mut i32 v783 = load v782 : i32 v784 = neq v783, 0 : i1 condbr v784, block94(v783), block97 +} block97: +{ br block92(v737, v773, v662, v682, v718) +} block98: +{ v787 = call noname::dlmalloc::dlmalloc::Segment::sys_flags(v775) : i32 v789 = neq v787, v729 : i1 v790 = cast v789 : i32 v791 = neq v790, 0 : i1 condbr v791, block92(v815, v818, v1092, v1484, v1509), block99 +} block99: +{ v793 = cast v654 : u32 v794 = add v793, 428 : u32 v795 = inttoptr v794 : *mut i32 @@ -2805,11 +3298,15 @@ block99: v797 = call noname::dlmalloc::dlmalloc::Segment::holds(v775, v796) : i32 v798 = neq v797, 0 : i1 condbr v798, block81, block100 +} block100: +{ br block92(v815, v818, v1092, v1484, v1509) +} block101: +{ v1069 = cast v819 : u32 v1070 = inttoptr v1069 : *mut i32 v1071 = load v1070 : i32 @@ -2847,20 +3344,26 @@ block101: v1103 = cast v1102 : i32 v1104 = neq v1103, 0 : i1 condbr v1104, block126, block127 +} block102(v840: i32, v846: i32, v912: i32, v925: i32, v1506: i32): +{ v842 = cast v840 : u32 v843 = add v842, 428 : u32 v844 = inttoptr v843 : *mut i32 v845 = load v844 : i32 br block111(v846) +} block103: +{ v832 = call noname::dlmalloc::dlmalloc::Segment::is_extern(v819) : i32 v833 = neq v832, 0 : i1 condbr v833, block102(v841, v847, v913, v926, v1507), block108 +} block104(v819: i32): +{ v820 = cast v819 : u32 v821 = inttoptr v820 : *mut i32 v822 = load v821 : i32 @@ -2868,31 +3371,43 @@ block104(v819: i32): v825 = cast v824 : i32 v826 = neq v825, 0 : i1 condbr v826, block103, block106 +} block105: +{ +} block106: +{ v827 = cast v819 : u32 v828 = add v827, 8 : u32 v829 = inttoptr v828 : *mut i32 v830 = load v829 : i32 v831 = neq v830, 0 : i1 condbr v831, block104(v830), block107 +} block107: +{ br block102(v799, v817, v804, v814, v1508) +} block108: +{ v834 = call noname::dlmalloc::dlmalloc::Segment::sys_flags(v819) : i32 v837 = eq v834, v788 : i1 v838 = cast v837 : i32 v839 = neq v838, 0 : i1 condbr v839, block101, block109 +} block109: +{ br block102(v841, v847, v913, v926, v1507) +} block110(v872: i32, v880: i32, v907: i32, v910: i32, v923: i32, v961: i32, v980: i32, v1446: i32, v1490: i32, v1504: i32): +{ v873 = call noname::dlmalloc::dlmalloc::Segment::top(v872) : i32 v874 = const.i32 20 : i32 v875 = const.i32 8 : i32 @@ -3009,8 +3524,10 @@ block110(v872: i32, v880: i32, v907: i32, v910: i32, v923: i32, v961: i32, v980: v996 = inttoptr v995 : *mut i32 store v996, v896 br block117(v897) +} block111(v848: i32): +{ v849 = cast v848 : u32 v850 = inttoptr v849 : *mut i32 v851 = load v850 : i32 @@ -3020,20 +3537,26 @@ block111(v848: i32): v856 = cast v855 : i32 v857 = neq v856, 0 : i1 condbr v857, block113, block114 +} block112: +{ v871 = const.i32 0 : i32 br block110(v871, v870, v909, v914, v927, v963, v983, v1449, v1493, v1510) +} block113: +{ v865 = cast v848 : u32 v866 = add v865, 8 : u32 v867 = inttoptr v866 : *mut i32 v868 = load v867 : i32 v869 = neq v868, 0 : i1 condbr v869, block111(v868), block116 +} block114: +{ v858 = call noname::dlmalloc::dlmalloc::Segment::top(v848) : i32 v859 = cast v858 : u32 v860 = cast v852 : u32 @@ -3041,14 +3564,20 @@ block114: v862 = cast v861 : i32 v863 = neq v862, 0 : i1 condbr v863, block110(v848, v852, v840, v912, v925, v846, v835, v1090, v1482, v1506), block115 +} block115: +{ br block113 +} block116: +{ br block112 +} block117(v997: i32): +{ v998 = const.i32 4 : i32 v999 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v997, v998) : i32 v1000 = call noname::dlmalloc::dlmalloc::Chunk::fencepost_head() : i32 @@ -3064,17 +3593,23 @@ block117(v997: i32): v1010 = cast v1009 : i32 v1011 = neq v1010, 0 : i1 condbr v1011, block117(v999), block119 +} block118: +{ v1014 = eq v895, v880 : i1 v1015 = cast v1014 : i32 v1016 = neq v1015, 0 : i1 condbr v1016, block76(v1025, v1446, v1490, v1504), block120 +} block119: +{ br block118 +} block120: +{ v1017 = sub v1012, v1013 : i32 v1018 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v1013, v1017) : i32 call noname::dlmalloc::dlmalloc::Chunk::set_free_with_pinuse(v1013, v1017, v1018) @@ -3085,8 +3620,10 @@ block120: v1023 = cast v1022 : i32 v1024 = neq v1023, 0 : i1 condbr v1024, block121, block122 +} block121: +{ v1026 = const.i32 -8 : i32 v1027 = band v1017, v1026 : i32 v1028 = add v1025, v1027 : i32 @@ -3108,12 +3645,16 @@ block121: v1044 = cast v1043 : i32 v1045 = neq v1044, 0 : i1 condbr v1045, block124, block125 +} block122: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk(v907, v1013, v1017) br block76(v1025, v1445, v1489, v1503) +} block123(v1059: i32): +{ v1056 = cast v1030 : u32 v1057 = add v1056, 8 : u32 v1058 = inttoptr v1057 : *mut i32 @@ -3131,23 +3672,29 @@ block123(v1059: i32): v1068 = inttoptr v1067 : *mut i32 store v1068, v1059 br block76(v1025, v1445, v1489, v1503) +} block124: +{ v1050 = bor v1034, v1041 : i32 v1051 = cast v1025 : u32 v1052 = add v1051, 408 : u32 v1053 = inttoptr v1052 : *mut i32 store v1053, v1050 br block123(v1030) +} block125: +{ v1046 = cast v1030 : u32 v1047 = add v1046, 8 : u32 v1048 = inttoptr v1047 : *mut i32 v1049 = load v1048 : i32 br block123(v1049) +} block126: +{ v1158 = cast v841 : u32 v1159 = add v1158, 428 : u32 v1160 = inttoptr v1159 : *mut i32 @@ -3169,8 +3716,10 @@ block126: store v1173, v1170 v1174 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v1089) : i32 br block2(v1483, v1174) +} block127: +{ v1105 = cast v841 : u32 v1106 = add v1105, 424 : u32 v1107 = inttoptr v1106 : *mut i32 @@ -3179,13 +3728,17 @@ block127: v1110 = cast v1109 : i32 v1111 = neq v1110, 0 : i1 condbr v1111, block80, block128 +} block128: +{ v1112 = call noname::dlmalloc::dlmalloc::Chunk::inuse(v1095) : i32 v1113 = neq v1112, 0 : i1 condbr v1113, block78(v1097, v1095), block129 +} block129: +{ v1114 = call noname::dlmalloc::dlmalloc::Chunk::size(v1095) : i32 v1115 = const.i32 256 : i32 v1116 = cast v1114 : u32 @@ -3194,13 +3747,17 @@ block129: v1119 = cast v1118 : i32 v1120 = neq v1119, 0 : i1 condbr v1120, block131, block132 +} block130: +{ v1155 = add v1114, v1097 : i32 v1157 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v1095, v1153) : i32 br block78(v1155, v1157) +} block131: +{ v1121 = cast v1095 : u32 v1122 = add v1121, 12 : u32 v1123 = inttoptr v1122 : *mut i32 @@ -3213,12 +3770,16 @@ block131: v1130 = cast v1129 : i32 v1131 = neq v1130, 0 : i1 condbr v1131, block133, block134 +} block132: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(v841, v1095) br block130 +} block133: +{ v1138 = cast v841 : u32 v1139 = add v1138, 408 : u32 v1140 = inttoptr v1139 : *mut i32 @@ -3236,8 +3797,10 @@ block133: v1152 = inttoptr v1151 : *mut i32 store v1152, v1149 br block130 +} block134: +{ v1132 = cast v1128 : u32 v1133 = add v1132, 12 : u32 v1134 = inttoptr v1133 : *mut i32 @@ -3247,8 +3810,10 @@ block134: v1137 = inttoptr v1136 : *mut i32 store v1137, v1128 br block130 +} block135: +{ v1206 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v1196, v662) : i32 v1207 = cast v654 : u32 v1208 = add v1207, 416 : u32 @@ -3262,8 +3827,10 @@ block135: call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk(v1196, v662) v1213 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v1196) : i32 br block2(v682, v1213) +} block136: +{ v1276 = const.i32 -8 : i32 v1277 = band v1263, v1276 : i32 v1278 = add v1271, v1277 : i32 @@ -3285,13 +3852,17 @@ block136: v1294 = cast v1293 : i32 v1295 = neq v1294, 0 : i1 condbr v1295, block139, block140 +} block137: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::insert_large_chunk(v841, v1261, v1263) v1275 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v1089) : i32 br block2(v1482, v1275) +} block138(v1309: i32): +{ v1306 = cast v1280 : u32 v1307 = add v1306, 8 : u32 v1308 = inttoptr v1307 : *mut i32 @@ -3310,23 +3881,29 @@ block138(v1309: i32): store v1318, v1309 v1320 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v1273) : i32 br block2(v1485, v1320) +} block139: +{ v1300 = bor v1284, v1291 : i32 v1301 = cast v1271 : u32 v1302 = add v1301, 408 : u32 v1303 = inttoptr v1302 : *mut i32 store v1303, v1300 br block138(v1280) +} block140: +{ v1296 = cast v1280 : u32 v1297 = add v1296, 8 : u32 v1298 = inttoptr v1297 : *mut i32 v1299 = load v1298 : i32 br block138(v1299) +} block141(v1344: i32): +{ v1345 = add v1343, v1344 : i32 v1346 = const.i32 164 : i32 v1347 = add v1345, v1346 : i32 @@ -3377,8 +3954,10 @@ block141(v1344: i32): v1384 = cast v1383 : i32 v1385 = neq v1384, 0 : i1 condbr v1385, block141(v1381), block143 +} block142: +{ v1386 = call noname::dlmalloc::dlmalloc::Chunk::mem_offset() : i32 v1387 = const.i32 8 : i32 v1388 = call noname::dlmalloc::dlmalloc::align_up(v1386, v1387) : i32 @@ -3435,11 +4014,15 @@ block142: v1437 = inttoptr v1436 : *mut i32 store v1437, v1434 br block76(v1343, v662, v682, v718) +} block143: +{ br block142 +} block144: +{ v1459 = sub v1443, v1444 : i32 v1460 = cast v1438 : u32 v1461 = add v1460, 420 : u32 @@ -3464,9 +4047,11 @@ block144: v1476 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v1466) : i32 br block2(v1488, v1476) } +} pub fn dlmalloc::dlmalloc::Dlmalloc::init_top(i32, i32, i32) { block0(v0: i32, v1: i32, v2: i32): +{ v3 = const.i32 0 : i32 v4 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v1) : i32 v5 = const.i32 8 : i32 @@ -3511,13 +4096,17 @@ block0(v0: i32, v1: i32, v2: i32): v40 = inttoptr v39 : *mut i32 store v40, v37 br block1 +} block1: - ret +{ + ret +} } pub fn dlmalloc::dlmalloc::Dlmalloc::memalign(i32, i32, i32) -> i32 { block0(v0: i32, v1: i32, v2: i32): +{ v4 = const.i32 0 : i32 v5 = const.i32 16 : i32 v6 = const.i32 8 : i32 @@ -3528,11 +4117,15 @@ block0(v0: i32, v1: i32, v2: i32): v11 = cast v10 : i32 v12 = neq v11, 0 : i1 condbr v12, block2(v1), block3 +} block1(v3: i32): - ret v3 +{ + ret (v3) +} block2(v48: i32): +{ v16 = call noname::dlmalloc::dlmalloc::Chunk::mem_offset() : i32 v17 = const.i32 8 : i32 v18 = call noname::dlmalloc::dlmalloc::align_up(v16, v17) : i32 @@ -3572,17 +4165,23 @@ block2(v48: i32): v54 = cast v53 : i32 v55 = neq v54, 0 : i1 condbr v55, block4(v25), block5 +} block3: +{ v13 = const.i32 16 : i32 v14 = const.i32 8 : i32 v15 = call noname::dlmalloc::dlmalloc::align_up(v13, v14) : i32 br block2(v15) +} block4(v140: i32): +{ br block1(v140) +} block5: +{ v57 = const.i32 16 : i32 v58 = const.i32 4 : i32 v59 = add v50, v58 : i32 @@ -3611,21 +4210,27 @@ block5: v82 = cast v81 : i32 v83 = neq v82, 0 : i1 condbr v83, block4(v25), block6 +} block6: +{ v84 = call noname::dlmalloc::dlmalloc::Chunk::from_mem(v80) : i32 v85 = const.i32 -1 : i32 v86 = add v48, v85 : i32 v87 = band v86, v80 : i32 v88 = neq v87, 0 : i1 condbr v88, block8, block9 +} block7(v120: i32): +{ v121 = call noname::dlmalloc::dlmalloc::Chunk::mmapped(v120) : i32 v122 = neq v121, 0 : i1 condbr v122, block12, block13 +} block8: +{ v89 = add v86, v80 : i32 v90 = const.i32 0 : i32 v91 = sub v90, v48 : i32 @@ -3649,11 +4254,15 @@ block8: v109 = call noname::dlmalloc::dlmalloc::Chunk::mmapped(v84) : i32 v110 = neq v109, 0 : i1 condbr v110, block10, block11 +} block9: +{ br block7(v84) +} block10: +{ v111 = cast v84 : u32 v112 = inttoptr v111 : *mut i32 v113 = load v112 : i32 @@ -3666,19 +4275,25 @@ block10: v119 = inttoptr v118 : *mut i32 store v119, v117 br block7(v106) +} block11: +{ call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v106, v108) call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v84, v107) call noname::dlmalloc::dlmalloc::Dlmalloc::dispose_chunk(v56, v84, v107) br block7(v106) +} block12: +{ v138 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v120) : i32 v139 = call noname::dlmalloc::dlmalloc::Chunk::mmapped(v137) : i32 br block4(v138) +} block13: +{ v123 = call noname::dlmalloc::dlmalloc::Chunk::size(v120) : i32 v124 = const.i32 16 : i32 v125 = const.i32 8 : i32 @@ -3690,8 +4305,10 @@ block13: v132 = cast v131 : i32 v133 = neq v132, 0 : i1 condbr v133, block12, block14 +} block14: +{ v134 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v120, v127) : i32 call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v120, v127) v135 = sub v123, v127 : i32 @@ -3699,18 +4316,24 @@ block14: call noname::dlmalloc::dlmalloc::Dlmalloc::dispose_chunk(v56, v134, v135) br block12 } +} pub fn __main() -> i32 { block0: +{ v1 = call noname::vec_alloc() : i32 br block1(v1) +} block1(v0: i32): - ret v0 +{ + ret (v0) +} } pub fn __rust_alloc(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = const.i32 0 : i32 v4 = global.load (@__stack_pointer) as *mut i8 : i32 v5 = const.i32 16 : i32 @@ -3728,11 +4351,15 @@ block0(v0: i32, v1: i32): v15 = cast v14 : i32 v16 = neq v15, 0 : i1 condbr v16, block3, block4 +} block1(v2: i32): - ret v2 +{ + ret (v2) +} block2(v25: i32): +{ v20 = const.i32 15 : i32 v21 = add v6, v20 : i32 call noname::::drop(v21) @@ -3741,18 +4368,24 @@ block2(v25: i32): v24 = global.symbol @__stack_pointer : *mut i32 store v24, v23 br block1(v25) +} block3: +{ v18 = call noname::dlmalloc::dlmalloc::Dlmalloc::malloc(v10, v0) : i32 br block2(v18) +} block4: +{ v17 = call noname::dlmalloc::dlmalloc::Dlmalloc::memalign(v10, v1, v0) : i32 br block2(v17) } +} pub fn __rust_dealloc(i32, i32, i32) { block0(v0: i32, v1: i32, v2: i32): +{ v3 = const.i32 0 : i32 v4 = global.load (@__stack_pointer) as *mut i8 : i32 v5 = const.i32 16 : i32 @@ -3772,13 +4405,17 @@ block0(v0: i32, v1: i32, v2: i32): v15 = global.symbol @__stack_pointer : *mut i32 store v15, v14 br block1 +} block1: - ret +{ + ret +} } pub fn __rust_realloc(i32, i32, i32, i32) -> i32 { block0(v0: i32, v1: i32, v2: i32, v3: i32): +{ v5 = const.i32 0 : i32 v6 = global.load (@__stack_pointer) as *mut i8 : i32 v7 = const.i32 16 : i32 @@ -3796,11 +4433,15 @@ block0(v0: i32, v1: i32, v2: i32, v3: i32): v17 = cast v16 : i32 v18 = neq v17, 0 : i1 condbr v18, block7, block8 +} block1(v4: i32): - ret v4 +{ + ret (v4) +} block2(v369: i32, v381: i32): +{ v376 = const.i32 15 : i32 v377 = add v369, v376 : i32 call noname::::drop(v377) @@ -3809,20 +4450,26 @@ block2(v369: i32, v381: i32): v380 = global.symbol @__stack_pointer : *mut i32 store v380, v379 br block1(v381) +} block3(v366: i32, v375: i32): +{ v367 = call noname::dlmalloc::dlmalloc::Chunk::mmapped(v366) : i32 v368 = call noname::dlmalloc::dlmalloc::Chunk::to_mem(v366) : i32 br block2(v375, v368) +} block4(v335: i32, v337: i32, v346: i32, v351: i32, v370: i32, v382: i32): +{ v342 = call noname::dlmalloc::dlmalloc::Dlmalloc::malloc(v335, v337) : i32 v343 = eq v342, 0 : i1 v344 = cast v343 : i32 v345 = neq v344, 0 : i1 condbr v345, block2(v370, v382), block45 +} block5: +{ v321 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v75, v74) : i32 call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v75, v74) v322 = cast v12 : u32 @@ -3842,8 +4489,10 @@ block5: store v333, v325 v334 = neq v75, 0 : i1 condbr v334, block3(v75, v8), block44 +} block6: +{ v314 = cast v1 : u32 v315 = cast v3 : u32 v316 = lt v314, v315 : i1 @@ -3853,8 +4502,10 @@ block6: v320 = call noname::memcpy(v19, v0, v319) : i32 call noname::dlmalloc::dlmalloc::Dlmalloc::free(v12, v0) br block2(v8, v19) +} block7: +{ v22 = call noname::dlmalloc::dlmalloc::Chunk::mem_offset() : i32 v23 = const.i32 8 : i32 v24 = call noname::dlmalloc::dlmalloc::align_up(v22, v23) : i32 @@ -3893,17 +4544,23 @@ block7: v57 = cast v56 : i32 v58 = neq v57, 0 : i1 condbr v58, block2(v8, v31), block10 +} block8: +{ v19 = call noname::dlmalloc::dlmalloc::Dlmalloc::memalign(v12, v2, v3) : i32 v20 = neq v19, 0 : i1 condbr v20, block6, block9 +} block9: +{ v21 = const.i32 0 : i32 br block2(v8, v21) +} block10: +{ v59 = const.i32 16 : i32 v60 = const.i32 4 : i32 v61 = add v3, v60 : i32 @@ -3926,8 +4583,10 @@ block10: v78 = call noname::dlmalloc::dlmalloc::Chunk::mmapped(v75) : i32 v79 = neq v78, 0 : i1 condbr v79, block17, block18 +} block11: +{ v304 = cast v12 : u32 v305 = add v304, 420 : u32 v306 = inttoptr v305 : *mut i32 @@ -3939,12 +4598,16 @@ block11: v312 = cast v311 : i32 v313 = neq v312, 0 : i1 condbr v313, block5, block43 +} block12: +{ v303 = neq v75, 0 : i1 condbr v303, block3(v302, v374), block42 +} block13: +{ v292 = sub v76, v74 : i32 v293 = const.i32 16 : i32 v294 = const.i32 8 : i32 @@ -3955,8 +4618,10 @@ block13: v299 = cast v298 : i32 v300 = neq v299, 0 : i1 condbr v300, block12, block41 +} block14: +{ v258 = cast v12 : u32 v259 = add v258, 416 : u32 v260 = inttoptr v259 : *mut i32 @@ -3968,8 +4633,10 @@ block14: v266 = cast v265 : i32 v267 = neq v266, 0 : i1 condbr v267, block4(v12, v3, v0, v75, v8, v31), block36 +} block15: +{ v243 = const.i32 16 : i32 v244 = const.i32 8 : i32 v245 = call noname::dlmalloc::dlmalloc::align_up(v243, v244) : i32 @@ -3979,8 +4646,10 @@ block15: v249 = cast v248 : i32 v250 = neq v249, 0 : i1 condbr v250, block32, block33 +} block16: +{ v210 = cast v77 : u32 v211 = add v210, 12 : u32 v212 = inttoptr v211 : *mut i32 @@ -3993,8 +4662,10 @@ block16: v219 = cast v218 : i32 v220 = neq v219, 0 : i1 condbr v220, block30, block31 +} block17: +{ v115 = call noname::dlmalloc::dlmalloc::Chunk::size(v75) : i32 v116 = const.i32 256 : i32 v117 = cast v74 : u32 @@ -4003,16 +4674,20 @@ block17: v120 = cast v119 : i32 v121 = neq v120, 0 : i1 condbr v121, block4(v12, v3, v0, v75, v8, v31), block25 +} block18: +{ v80 = cast v76 : u32 v81 = cast v74 : u32 v82 = gte v80, v81 : i1 v83 = cast v82 : i32 v84 = neq v83, 0 : i1 condbr v84, block13, block19 +} block19: +{ v85 = cast v12 : u32 v86 = add v85, 428 : u32 v87 = inttoptr v86 : *mut i32 @@ -4021,8 +4696,10 @@ block19: v90 = cast v89 : i32 v91 = neq v90, 0 : i1 condbr v91, block11, block20 +} block20: +{ v92 = cast v12 : u32 v93 = add v92, 424 : u32 v94 = inttoptr v93 : *mut i32 @@ -4031,13 +4708,17 @@ block20: v97 = cast v96 : i32 v98 = neq v97, 0 : i1 condbr v98, block14, block21 +} block21: +{ v99 = call noname::dlmalloc::dlmalloc::Chunk::cinuse(v77) : i32 v100 = neq v99, 0 : i1 condbr v100, block4(v12, v3, v0, v75, v8, v31), block22 +} block22: +{ v101 = call noname::dlmalloc::dlmalloc::Chunk::size(v77) : i32 v102 = add v101, v76 : i32 v103 = cast v102 : u32 @@ -4046,8 +4727,10 @@ block22: v106 = cast v105 : i32 v107 = neq v106, 0 : i1 condbr v107, block4(v12, v3, v0, v75, v8, v31), block23 +} block23: +{ v108 = sub v102, v74 : i32 v109 = const.i32 256 : i32 v110 = cast v101 : u32 @@ -4056,12 +4739,16 @@ block23: v113 = cast v112 : i32 v114 = neq v113, 0 : i1 condbr v114, block16, block24 +} block24: +{ call noname::dlmalloc::dlmalloc::Dlmalloc::unlink_large_chunk(v12, v77) br block15 +} block25: +{ v122 = const.i32 4 : i32 v123 = add v74, v122 : i32 v124 = cast v115 : u32 @@ -4070,8 +4757,10 @@ block25: v127 = cast v126 : i32 v128 = neq v127, 0 : i1 condbr v128, block26, block27 +} block26: +{ v138 = cast v137 : u32 v139 = inttoptr v138 : *mut i32 v140 = load v139 : i32 @@ -4089,8 +4778,10 @@ block26: v154 = cast v153 : i32 v155 = neq v154, 0 : i1 condbr v155, block4(v136, v3, v0, v137, v8, v31), block29 +} block27: +{ v129 = sub v115, v74 : i32 v130 = const.i32 131073 : i32 v131 = cast v129 : u32 @@ -4099,11 +4790,15 @@ block27: v134 = cast v133 : i32 v135 = neq v134, 0 : i1 condbr v135, block12, block28 +} block28: +{ br block26 +} block29: +{ v156 = add v152, v140 : i32 v157 = sub v150, v140 : i32 v158 = const.i32 -16 : i32 @@ -4165,8 +4860,10 @@ block29: v209 = inttoptr v208 : *mut i32 store v209, v206 br block3(v156, v371) +} block30: +{ v227 = cast v12 : u32 v228 = add v227, 408 : u32 v229 = inttoptr v228 : *mut i32 @@ -4184,8 +4881,10 @@ block30: v241 = inttoptr v240 : *mut i32 store v241, v238 br block15 +} block31: +{ v221 = cast v217 : u32 v222 = add v221, 12 : u32 v223 = inttoptr v222 : *mut i32 @@ -4195,27 +4894,37 @@ block31: v226 = inttoptr v225 : *mut i32 store v226, v217 br block15 +} block32: +{ call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v251, v102) v257 = neq v251, 0 : i1 condbr v257, block3(v251, v372), block35 +} block33: +{ v253 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v75, v74) : i32 call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v251, v252) call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v253, v242) call noname::dlmalloc::dlmalloc::Dlmalloc::dispose_chunk(v12, v253, v242) v255 = neq v251, 0 : i1 condbr v255, block3(v251, v372), block34 +} block34: +{ br block4(v254, v3, v0, v251, v8, v31) +} block35: +{ br block4(v254, v339, v348, v251, v372, v384) +} block36: +{ v268 = sub v262, v74 : i32 v269 = const.i32 16 : i32 v270 = const.i32 8 : i32 @@ -4226,8 +4935,10 @@ block36: v275 = cast v274 : i32 v276 = neq v275, 0 : i1 condbr v276, block38, block39 +} block37(v282: i32, v286: i32): +{ v283 = cast v12 : u32 v284 = add v283, 424 : u32 v285 = inttoptr v284 : *mut i32 @@ -4238,41 +4949,57 @@ block37(v282: i32, v286: i32): store v289, v286 v291 = neq v75, 0 : i1 condbr v291, block3(v290, v373), block40 +} block38: +{ v279 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v75, v74) : i32 v280 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v279, v268) : i32 call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v75, v74) call noname::dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk(v279, v268) call noname::dlmalloc::dlmalloc::Chunk::clear_pinuse(v280) br block37(v279, v268) +} block39: +{ call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v75, v262) v277 = const.i32 0 : i32 v278 = const.i32 0 : i32 br block37(v278, v277) +} block40: +{ br block4(v281, v3, v0, v290, v8, v31) +} block41: +{ v301 = call noname::dlmalloc::dlmalloc::Chunk::plus_offset(v75, v74) : i32 call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v75, v74) call noname::dlmalloc::dlmalloc::Chunk::set_inuse(v301, v292) call noname::dlmalloc::dlmalloc::Dlmalloc::dispose_chunk(v12, v301, v292) br block12 +} block42: +{ br block4(v12, v3, v0, v302, v8, v31) +} block43: +{ br block4(v12, v3, v0, v75, v8, v31) +} block44: +{ br block4(v12, v3, v0, v75, v8, v31) +} block45: +{ v352 = call noname::dlmalloc::dlmalloc::Chunk::size(v351) : i32 v353 = const.i32 -8 : i32 v354 = const.i32 -4 : i32 @@ -4290,42 +5017,56 @@ block45: call noname::dlmalloc::dlmalloc::Dlmalloc::free(v335, v346) br block2(v370, v365) } +} pub fn __rust_alloc_error_handler(i32, i32) { block0(v0: i32, v1: i32): +{ call noname::__rdl_oom(v0, v1) - ret + ret +} block1: +{ +} } pub fn alloc::raw_vec::finish_grow(i32, i32, i32, i32) { block0(v0: i32, v1: i32, v2: i32, v3: i32): +{ v4 = const.i32 0 : i32 v5 = eq v1, 0 : i1 v6 = cast v5 : i32 v7 = neq v6, 0 : i1 condbr v7, block4, block5 +} block1: - ret +{ + ret +} block2(v83: i32): +{ v84 = const.i32 1 : i32 v85 = cast v83 : u32 v86 = inttoptr v85 : *mut i32 store v86, v84 br block1 +} block3: +{ v79 = const.i32 0 : i32 v80 = cast v0 : u32 v81 = add v80, 4 : u32 v82 = inttoptr v81 : *mut i32 store v82, v79 br block2(v0) +} block4: +{ v71 = const.i32 0 : i32 v72 = cast v0 : u32 v73 = add v72, 4 : u32 @@ -4337,15 +5078,19 @@ block4: v78 = inttoptr v77 : *mut i32 store v78, v2 br block2(v0) +} block5: +{ v8 = const.i32 -1 : i32 v9 = lte v2, v8 : i1 v10 = cast v9 : i32 v11 = neq v10, 0 : i1 condbr v11, block3, block6 +} block6: +{ v12 = cast v3 : u32 v13 = add v12, 4 : u32 v14 = inttoptr v13 : *mut i32 @@ -4354,22 +5099,30 @@ block6: v17 = cast v16 : i32 v18 = neq v17, 0 : i1 condbr v18, block9, block10 +} block7(v46: i32, v57: i32, v63: i32): +{ v47 = eq v46, 0 : i1 v48 = cast v47 : i32 v49 = neq v48, 0 : i1 condbr v49, block17, block18 +} block8: +{ v45 = call noname::__rust_alloc(v2, v1) : i32 br block7(v45, v43, v44) +} block9: +{ v36 = neq v2, 0 : i1 condbr v36, block15, block16 +} block10: +{ v19 = const.i32 8 : i32 v20 = add v3, v19 : i32 v21 = cast v20 : u32 @@ -4377,19 +5130,25 @@ block10: v23 = load v22 : i32 v24 = neq v23, 0 : i1 condbr v24, block11, block12 +} block11: +{ v32 = cast v3 : u32 v33 = inttoptr v32 : *mut i32 v34 = load v33 : i32 v35 = call noname::__rust_realloc(v34, v23, v1, v2) : i32 br block7(v35, v2, v1) +} block12: +{ v25 = neq v2, 0 : i1 condbr v25, block13, block14 +} block13: +{ v26 = const.i32 0 : i32 v27 = cast v26 : u32 v28 = add v27, 1048576 : u32 @@ -4397,11 +5156,15 @@ block13: v30 = load v29 : u8 v31 = zext v30 : i32 br block8 +} block14: +{ br block7(v1, v2, v1) +} block15: +{ v37 = const.i32 0 : i32 v38 = cast v37 : u32 v39 = add v38, 1048576 : u32 @@ -4409,11 +5172,15 @@ block15: v41 = load v40 : u8 v42 = zext v41 : i32 br block8 +} block16: +{ br block7(v1, v2, v1) +} block17: +{ v64 = cast v50 : u32 v65 = add v64, 4 : u32 v66 = inttoptr v65 : *mut i32 @@ -4424,8 +5191,10 @@ block17: v70 = inttoptr v69 : *mut i32 store v70, v57 br block2(v50) +} block18: +{ v52 = cast v0 : u32 v53 = add v52, 4 : u32 v54 = inttoptr v53 : *mut i32 @@ -4439,11 +5208,13 @@ block18: v61 = cast v50 : u32 v62 = inttoptr v61 : *mut i32 store v62, v60 - ret + ret +} } pub fn alloc::raw_vec::RawVec::reserve_for_push(i32) { block0(v0: i32): +{ v1 = const.i32 0 : i32 v2 = global.load (@__stack_pointer) as *mut i8 : i32 v3 = const.i32 32 : i32 @@ -4477,11 +5248,15 @@ block0(v0: i32): v30 = cast v29 : i32 v31 = neq v30, 0 : i1 condbr v31, block3, block4 +} block1: - ret +{ + ret +} block2: +{ v52 = const.i32 8 : i32 v53 = add v4, v52 : i32 v56 = const.i32 20 : i32 @@ -4497,16 +5272,20 @@ block2: v65 = load v64 : i32 v66 = neq v65, 0 : i1 condbr v66, block6, block7 +} block3: +{ v47 = const.i32 0 : i32 v48 = cast v4 : u32 v49 = add v48, 24 : u32 v50 = inttoptr v49 : *mut i32 store v50, v47 br block2 +} block4: +{ v32 = const.i32 4 : i32 v33 = cast v4 : u32 v34 = add v33, 24 : u32 @@ -4526,22 +5305,28 @@ block4: v46 = inttoptr v45 : *mut i32 store v46, v43 br block2 +} block5: +{ v87 = const.i32 32 : i32 v88 = add v51, v87 : i32 v89 = global.symbol @__stack_pointer : *mut i32 store v89, v88 br block1 +} block6: +{ v74 = const.i32 -2147483647 : i32 v75 = eq v61, v74 : i1 v76 = cast v75 : i32 v77 = neq v76, 0 : i1 condbr v77, block5, block8 +} block7: +{ v69 = cast v0 : u32 v70 = add v69, 4 : u32 v71 = inttoptr v70 : *mut i32 @@ -4550,18 +5335,24 @@ block7: v73 = inttoptr v72 : *mut i32 store v73, v61 br block5 +} block8: +{ v78 = eq v61, 0 : i1 v79 = cast v78 : i32 v80 = neq v79, 0 : i1 condbr v80, block9, block10 +} block9: +{ call noname::alloc::raw_vec::capacity_overflow() unreachable +} block10: +{ v81 = const.i32 16 : i32 v82 = add v51, v81 : i32 v83 = cast v82 : u32 @@ -4570,9 +5361,11 @@ block10: call noname::alloc::alloc::handle_alloc_error(v61, v85) unreachable } +} pub fn vec_alloc() -> i32 { block0: +{ v1 = const.i32 0 : i32 v2 = global.load (@__stack_pointer) as *mut i8 : i32 v3 = const.i32 16 : i32 @@ -4612,13 +5405,19 @@ block0: v32 = cast v31 : i32 v33 = neq v32, 0 : i1 condbr v33, block2, block3 +} block1(v0: i32): +{ +} block2: +{ unreachable +} block3: +{ v34 = cast v4 : u32 v35 = add v34, 8 : u32 v36 = inttoptr v35 : *mut i32 @@ -4627,55 +5426,77 @@ block3: v39 = cast v38 : i32 v40 = neq v39, 0 : i1 condbr v40, block4, block5 +} block4: +{ v45 = const.i32 16 : i32 v46 = add v4, v45 : i32 v47 = global.symbol @__stack_pointer : *mut i32 store v47, v46 v48 = const.i32 1 : i32 - ret v48 + ret (v48) +} block5: +{ v41 = const.i32 2 : i32 v42 = shl v37, v41 : i32 v43 = const.i32 4 : i32 call noname::__rust_dealloc(v19, v42, v43) br block4 } +} pub fn alloc::raw_vec::capacity_overflow() { block0: +{ unreachable +} block1: +{ +} } pub fn alloc::alloc::handle_alloc_error(i32, i32) { block0(v0: i32, v1: i32): +{ call noname::alloc::alloc::handle_alloc_error::rt_error(v0, v1) unreachable +} block1: +{ +} } pub fn alloc::alloc::handle_alloc_error::rt_error(i32, i32) { block0(v0: i32, v1: i32): +{ call noname::__rust_alloc_error_handler(v1, v0) unreachable +} block1: +{ +} } pub fn __rdl_oom(i32, i32) { block0(v0: i32, v1: i32): +{ unreachable +} block1: +{ +} } pub fn dlmalloc::dlmalloc::align_up(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = add v0, v1 : i32 v4 = const.i32 -1 : i32 v5 = add v3, v4 : i32 @@ -4683,37 +5504,49 @@ block0(v0: i32, v1: i32): v7 = sub v6, v1 : i32 v8 = band v5, v7 : i32 br block1(v8) +} block1(v2: i32): - ret v2 +{ + ret (v2) +} } pub fn dlmalloc::dlmalloc::left_bits(i32) -> i32 { block0(v0: i32): +{ v2 = const.i32 1 : i32 v3 = shl v0, v2 : i32 v4 = const.i32 0 : i32 v5 = sub v4, v3 : i32 v6 = bor v3, v5 : i32 br block1(v6) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::least_bit(i32) -> i32 { block0(v0: i32): +{ v2 = const.i32 0 : i32 v3 = sub v2, v0 : i32 v4 = band v3, v0 : i32 br block1(v4) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::leftshift_for_tree_index(i32) -> i32 { block0(v0: i32): +{ v2 = const.i32 0 : i32 v3 = const.i32 25 : i32 v4 = const.i32 1 : i32 @@ -4728,22 +5561,30 @@ block0(v0: i32): v13 = neq v12, 0 : i1 v14 = select v13, v2, v9 : i32 br block1(v14) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Chunk::fencepost_head() -> i32 { block0: +{ v1 = const.i32 7 : i32 br block1(v1) +} block1(v0: i32): - ret v0 +{ + ret (v0) +} } pub fn dlmalloc::dlmalloc::Chunk::size(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = add v2, 4 : u32 v4 = inttoptr v3 : *mut i32 @@ -4751,13 +5592,17 @@ block0(v0: i32): v6 = const.i32 -8 : i32 v7 = band v5, v6 : i32 br block1(v7) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Chunk::cinuse(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = add v2, 4 : u32 v4 = inttoptr v3 : *mut u8 @@ -4771,13 +5616,17 @@ block0(v0: i32): v12 = shr v10, v11 : u32 v13 = cast v12 : i32 br block1(v13) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Chunk::pinuse(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = add v2, 4 : u32 v4 = inttoptr v3 : *mut i32 @@ -4785,13 +5634,17 @@ block0(v0: i32): v6 = const.i32 1 : i32 v7 = band v5, v6 : i32 br block1(v7) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Chunk::clear_pinuse(i32) { block0(v0: i32): +{ v1 = cast v0 : u32 v2 = add v1, 4 : u32 v3 = inttoptr v2 : *mut i32 @@ -4803,13 +5656,17 @@ block0(v0: i32): v9 = inttoptr v8 : *mut i32 store v9, v6 br block1 +} block1: - ret +{ + ret +} } pub fn dlmalloc::dlmalloc::Chunk::inuse(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = add v2, 4 : u32 v4 = inttoptr v3 : *mut i32 @@ -4820,13 +5677,17 @@ block0(v0: i32): v9 = neq v7, v8 : i1 v10 = cast v9 : i32 br block1(v10) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Chunk::mmapped(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = add v2, 4 : u32 v4 = inttoptr v3 : *mut u8 @@ -4837,13 +5698,17 @@ block0(v0: i32): v9 = eq v8, 0 : i1 v10 = cast v9 : i32 br block1(v10) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Chunk::set_inuse(i32, i32) { block0(v0: i32, v1: i32): +{ v2 = cast v0 : u32 v3 = add v2, 4 : u32 v4 = inttoptr v3 : *mut i32 @@ -4869,13 +5734,17 @@ block0(v0: i32, v1: i32): v23 = inttoptr v22 : *mut i32 store v23, v20 br block1 +} block1: - ret +{ + ret +} } pub fn dlmalloc::dlmalloc::Chunk::set_inuse_and_pinuse(i32, i32) { block0(v0: i32, v1: i32): +{ v2 = const.i32 3 : i32 v3 = bor v1, v2 : i32 v4 = cast v0 : u32 @@ -4894,13 +5763,17 @@ block0(v0: i32, v1: i32): v16 = inttoptr v15 : *mut i32 store v16, v13 br block1 +} block1: - ret +{ + ret +} } pub fn dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_inuse_chunk(i32, i32) { block0(v0: i32, v1: i32): +{ v2 = const.i32 3 : i32 v3 = bor v1, v2 : i32 v4 = cast v0 : u32 @@ -4908,13 +5781,17 @@ block0(v0: i32, v1: i32): v6 = inttoptr v5 : *mut i32 store v6, v3 br block1 +} block1: - ret +{ + ret +} } pub fn dlmalloc::dlmalloc::Chunk::set_size_and_pinuse_of_free_chunk(i32, i32) { block0(v0: i32, v1: i32): +{ v2 = const.i32 1 : i32 v3 = bor v1, v2 : i32 v4 = cast v0 : u32 @@ -4926,13 +5803,17 @@ block0(v0: i32, v1: i32): v9 = inttoptr v8 : *mut i32 store v9, v1 br block1 +} block1: - ret +{ + ret +} } pub fn dlmalloc::dlmalloc::Chunk::set_free_with_pinuse(i32, i32, i32) { block0(v0: i32, v1: i32, v2: i32): +{ v3 = cast v2 : u32 v4 = add v3, 4 : u32 v5 = inttoptr v4 : *mut i32 @@ -4954,60 +5835,84 @@ block0(v0: i32, v1: i32, v2: i32): v19 = inttoptr v18 : *mut i32 store v19, v1 br block1 +} block1: - ret +{ + ret +} } pub fn dlmalloc::dlmalloc::Chunk::plus_offset(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = add v0, v1 : i32 br block1(v3) +} block1(v2: i32): - ret v2 +{ + ret (v2) +} } pub fn dlmalloc::dlmalloc::Chunk::minus_offset(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = sub v0, v1 : i32 br block1(v3) +} block1(v2: i32): - ret v2 +{ + ret (v2) +} } pub fn dlmalloc::dlmalloc::Chunk::to_mem(i32) -> i32 { block0(v0: i32): +{ v2 = const.i32 8 : i32 v3 = add v0, v2 : i32 br block1(v3) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Chunk::mem_offset() -> i32 { block0: +{ v1 = const.i32 8 : i32 br block1(v1) +} block1(v0: i32): - ret v0 +{ + ret (v0) +} } pub fn dlmalloc::dlmalloc::Chunk::from_mem(i32) -> i32 { block0(v0: i32): +{ v2 = const.i32 -8 : i32 v3 = add v0, v2 : i32 br block1(v3) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::TreeChunk::leftmost_child(i32) -> i32 { block0(v0: i32): +{ v2 = const.i32 0 : i32 v3 = cast v0 : u32 v4 = add v3, 16 : u32 @@ -5015,14 +5920,20 @@ block0(v0: i32): v6 = load v5 : i32 v7 = neq v6, 0 : i1 condbr v7, block2(v6), block3 +} block1(v1: i32): - ret v1 +{ + ret (v1) +} block2(v13: i32): +{ br block1(v13) +} block3: +{ v8 = const.i32 20 : i32 v9 = add v0, v8 : i32 v10 = cast v9 : u32 @@ -5030,41 +5941,55 @@ block3: v12 = load v11 : i32 br block2(v12) } +} pub fn dlmalloc::dlmalloc::TreeChunk::chunk(i32) -> i32 { block0(v0: i32): +{ br block1(v0) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::TreeChunk::next(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = add v2, 12 : u32 v4 = inttoptr v3 : *mut i32 v5 = load v4 : i32 br block1(v5) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::TreeChunk::prev(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = add v2, 8 : u32 v4 = inttoptr v3 : *mut i32 v5 = load v4 : i32 br block1(v5) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Segment::is_extern(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = add v2, 12 : u32 v4 = inttoptr v3 : *mut i32 @@ -5072,13 +5997,17 @@ block0(v0: i32): v6 = const.i32 1 : i32 v7 = band v5, v6 : i32 br block1(v7) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Segment::sys_flags(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = add v2, 12 : u32 v4 = inttoptr v3 : *mut i32 @@ -5089,13 +6018,17 @@ block0(v0: i32): v9 = shr v7, v8 : u32 v10 = cast v9 : i32 br block1(v10) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::dlmalloc::Segment::holds(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = const.i32 0 : i32 v4 = const.i32 0 : i32 v5 = cast v0 : u32 @@ -5107,14 +6040,20 @@ block0(v0: i32, v1: i32): v11 = cast v10 : i32 v12 = neq v11, 0 : i1 condbr v12, block2(v4), block3 +} block1(v2: i32): - ret v2 +{ + ret (v2) +} block2(v22: i32): +{ br block1(v22) +} block3: +{ v13 = cast v0 : u32 v14 = add v13, 4 : u32 v15 = inttoptr v14 : *mut i32 @@ -5126,9 +6065,11 @@ block3: v21 = cast v20 : i32 br block2(v21) } +} pub fn dlmalloc::dlmalloc::Segment::top(i32) -> i32 { block0(v0: i32): +{ v2 = cast v0 : u32 v3 = inttoptr v2 : *mut i32 v4 = load v3 : i32 @@ -5138,30 +6079,42 @@ block0(v0: i32): v8 = load v7 : i32 v9 = add v4, v8 : i32 br block1(v9) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn ::deref_mut(i32) -> i32 { block0(v0: i32): +{ v2 = const.i32 1048580 : i32 br block1(v2) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn ::drop(i32) { block0(v0: i32): +{ br block1 +} block1: - ret +{ + ret +} } pub fn ::alloc(i32, i32, i32) { block0(v0: i32, v1: i32, v2: i32): +{ v3 = const.i32 0 : i32 v4 = const.i32 16 : i32 v5 = cast v2 : u32 @@ -5196,75 +6149,107 @@ block0(v0: i32, v1: i32, v2: i32): v32 = inttoptr v31 : *mut i32 store v32, v30 br block1 +} block1: - ret +{ + ret +} } pub fn ::remap(i32, i32, i32, i32, i32) -> i32 { block0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i32): +{ v6 = const.i32 0 : i32 br block1(v6) +} block1(v5: i32): - ret v5 +{ + ret (v5) +} } pub fn ::free_part(i32, i32, i32, i32) -> i32 { block0(v0: i32, v1: i32, v2: i32, v3: i32): +{ v5 = const.i32 0 : i32 br block1(v5) +} block1(v4: i32): - ret v4 +{ + ret (v4) +} } pub fn ::free(i32, i32, i32) -> i32 { block0(v0: i32, v1: i32, v2: i32): +{ v4 = const.i32 0 : i32 br block1(v4) +} block1(v3: i32): - ret v3 +{ + ret (v3) +} } pub fn ::can_release_part(i32, i32) -> i32 { block0(v0: i32, v1: i32): +{ v3 = const.i32 0 : i32 br block1(v3) +} block1(v2: i32): - ret v2 +{ + ret (v2) +} } pub fn ::page_size(i32) -> i32 { block0(v0: i32): +{ v2 = const.i32 65536 : i32 br block1(v2) +} block1(v1: i32): - ret v1 +{ + ret (v1) +} } pub fn dlmalloc::sys::enable_alloc_after_fork() { block0: +{ br block1 +} block1: - ret +{ + ret +} } pub fn memcpy(i32, i32, i32) -> i32 { block0(v0: i32, v1: i32, v2: i32): +{ v4 = call noname::compiler_builtins::mem::memcpy(v0, v1, v2) : i32 br block1(v4) +} block1(v3: i32): - ret v3 +{ + ret (v3) +} } pub fn compiler_builtins::mem::memcpy(i32, i32, i32) -> i32 { block0(v0: i32, v1: i32, v2: i32): +{ v4 = const.i32 0 : i32 v5 = const.i32 15 : i32 v6 = cast v2 : u32 @@ -5273,17 +6258,23 @@ block0(v0: i32, v1: i32, v2: i32): v9 = cast v8 : i32 v10 = neq v9, 0 : i1 condbr v10, block3, block4 +} block1(v3: i32): - ret v3 +{ + ret (v3) +} block2(v133: i32, v137: i32, v159: i32, v161: i32): +{ v134 = eq v133, 0 : i1 v135 = cast v134 : i32 v136 = neq v135, 0 : i1 condbr v136, block21, block22 +} block3: +{ v11 = const.i32 0 : i32 v12 = sub v11, v0 : i32 v13 = const.i32 3 : i32 @@ -5293,11 +6284,15 @@ block3: v17 = cast v16 : i32 v18 = neq v17, 0 : i1 condbr v18, block5(v15), block6 +} block4: +{ br block2(v2, v0, v1, v0) +} block5(v38: i32): +{ v43 = sub v2, v14 : i32 v44 = const.i32 -4 : i32 v45 = band v43, v44 : i32 @@ -5309,11 +6304,15 @@ block5(v38: i32): v53 = cast v52 : i32 v54 = neq v53, 0 : i1 condbr v54, block11, block12 +} block6: +{ br block7(v0, v1) +} block7(v19: i32, v20: i32): +{ v21 = cast v20 : u32 v22 = inttoptr v21 : *mut u8 v23 = load v22 : u8 @@ -5332,34 +6331,46 @@ block7(v19: i32, v20: i32): v36 = cast v35 : i32 v37 = neq v36, 0 : i1 condbr v37, block7(v31, v29), block9 +} block8: +{ br block5(v32) +} block9: +{ br block8 +} block10(v138: i32, v162: i32): +{ v124 = const.i32 3 : i32 v125 = band v43, v124 : i32 v132 = add v49, v45 : i32 br block2(v125, v138, v132, v162) +} block11: +{ v100 = const.i32 1 : i32 v101 = lt v45, v100 : i1 v102 = cast v101 : i32 v103 = neq v102, 0 : i1 condbr v103, block10(v46, v163), block17 +} block12: +{ v55 = const.i32 1 : i32 v56 = lt v45, v55 : i1 v57 = cast v56 : i32 v58 = neq v57, 0 : i1 condbr v58, block10(v46, v0), block13 +} block13: +{ v59 = const.i32 3 : i32 v60 = shl v49, v59 : i32 v61 = const.i32 24 : i32 @@ -5376,8 +6387,10 @@ block13: v72 = inttoptr v71 : *mut i32 v73 = load v72 : i32 br block14(v38, v73, v66) +} block14(v74: i32, v75: i32, v81: i32): +{ v77 = cast v75 : u32 v78 = cast v76 : u32 v79 = shr v77, v78 : u32 @@ -5400,16 +6413,24 @@ block14(v74: i32, v75: i32, v81: i32): v98 = cast v97 : i32 v99 = neq v98, 0 : i1 condbr v99, block14(v93, v84, v91), block16 +} block15: +{ +} block16: +{ br block10(v94, v163) +} block17: +{ br block18(v38, v49) +} block18(v104: i32, v105: i32): +{ v106 = cast v105 : u32 v107 = inttoptr v106 : *mut i32 v108 = load v107 : i32 @@ -5426,21 +6447,31 @@ block18(v104: i32, v105: i32): v119 = cast v118 : i32 v120 = neq v119, 0 : i1 condbr v120, block18(v114, v112), block20 +} block19: +{ br block10(v115, v163) +} block20: +{ br block19 +} block21: +{ br block1(v161) +} block22: +{ v139 = add v137, v133 : i32 br block23(v137, v159) +} block23(v140: i32, v141: i32): +{ v142 = cast v141 : u32 v143 = inttoptr v142 : *mut u8 v144 = load v143 : u8 @@ -5459,10 +6490,15 @@ block23(v140: i32, v141: i32): v157 = cast v156 : i32 v158 = neq v157, 0 : i1 condbr v158, block23(v152, v150), block25 +} block24: +{ br block21 +} block25: +{ br block24 } +} From fff84469e97c45ef40af3d663588230d3531dd69 Mon Sep 17 00:00:00 2001 From: Jacob Johannsen Date: Wed, 25 Oct 2023 11:37:23 +0200 Subject: [PATCH 12/12] Remove commented out code from tests/mod.rs --- hir/src/parser/parser/tests/mod.rs | 576 ----------------------------- 1 file changed, 576 deletions(-) diff --git a/hir/src/parser/parser/tests/mod.rs b/hir/src/parser/parser/tests/mod.rs index 7263d41c3..04ec48e40 100644 --- a/hir/src/parser/parser/tests/mod.rs +++ b/hir/src/parser/parser/tests/mod.rs @@ -1,33 +1,9 @@ use crate::parser::ast::*; use crate::{ArgumentExtension, ArgumentPurpose, CallConv, FunctionIdent, Ident, Linkage, Overflow, StructType, Type}; -//macro_rules! assert_matches { -// ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { -// match $left { -// $( $pattern )|+ $( if $guard )? => {} -// ref left_val => { -// panic!(r#"assertion failed: `(left matches right)` -// left: `{:?}`, -// right: `{:?}`"#, -// left_val, stringify!($($pattern)|+ $(if $guard)?)); -// } -// } -// } -//} - mod utils; use self::utils::ParseTest; -//macro_rules! assert_module_error { -// ($source:expr, $pattern:pat_param) => { -// if let Err(err) = ParseTest::new().parse_module($source) { -// assert_matches!(err, $pattern) -// } else { -// panic!("expected parsing to fail, but it succeeded"); -// } -// }; -//} - macro_rules! ident { ($name:ident) => { Ident::new( @@ -35,20 +11,6 @@ macro_rules! ident { miden_diagnostics::SourceSpan::UNKNOWN, ) }; -// -// ($name:literal) => { -// Identifier::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// crate::Symbol::intern($name), -// ) -// }; -// -// ($module:ident, $name:ident) => { -// QualifiedIdentifier::new( -// ident!($module), -// NamespacedIdentifier::Binding(ident!($name)), -// ) -// }; } macro_rules! function_ident { @@ -60,544 +22,6 @@ macro_rules! function_ident { }; } -// -//#[allow(unused)] -//macro_rules! global { -// ($name:ident, $offset:literal, $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Global(ident!($name)), -// access_type: AccessType::Default, -// offset: $offset, -// ty: Some($ty), -// }) -// }; -// -// ($name:ident, $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Global(ident!($name)), -// access_type: AccessType::Default, -// offset: 0, -// ty: Some($ty), -// }) -// }; -// -// ($name:literal, $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Global(ident!($name)), -// access_type: AccessType::Default, -// offset: 0, -// ty: Some($ty), -// }) -// }; -//} -// -//macro_rules! access { -// ($name:ident) => { -// ScalarExpr::SymbolAccess(SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Default, -// 0, -// )) -// }; -// -// ($name:literal) => { -// ScalarExpr::SymbolAccess(SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Default, -// 0, -// )) -// }; -// -// ($module:ident, $name:ident, $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Resolved(ident!($module, $name)), -// access_type: AccessType::Default, -// offset: 0, -// ty: Some($ty), -// }) -// }; -// -// ($name:ident, $offset:literal) => { -// ScalarExpr::SymbolAccess(SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Default, -// $offset, -// )) -// }; -// -// ($name:literal, $offset:literal) => { -// ScalarExpr::SymbolAccess(SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Default, -// $offset, -// )) -// }; -// -// ($name:ident, $offset:literal, $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Local(ident!($name)), -// access_type: AccessType::Default, -// offset: $offset, -// ty: Some($ty), -// }) -// }; -// -// ($name:ident, $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Local(ident!($name)), -// access_type: AccessType::Default, -// offset: 0, -// ty: Some($ty), -// }) -// }; -// -// ($name:literal, $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Local(ident!($name)), -// access_type: AccessType::Default, -// offset: 0, -// ty: Some($ty), -// }) -// }; -// -// ($name:ident [ $idx:literal ]) => { -// ScalarExpr::SymbolAccess(SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Index($idx), -// 0, -// )) -// }; -// -// ($name:literal [ $idx:literal ]) => { -// ScalarExpr::SymbolAccess(SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Index($idx), -// 0, -// )) -// }; -// -// ($name:ident [ $row:literal ] [ $col:literal ]) => { -// ScalarExpr::SymbolAccess(SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Matrix($row, $col), -// 0, -// )) -// }; -// -// ($name:ident [ $row:literal ] [ $col:literal ], $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Local(ident!($name)), -// access_type: AccessType::Matrix($row, $col), -// offset: 0, -// ty: Some($ty), -// }) -// }; -// -// ($module:ident, $name:ident [ $idx:literal ], $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ident!($module, $name).into(), -// access_type: AccessType::Index($idx), -// offset: 0, -// ty: Some($ty), -// }) -// }; -// -// ($module:ident, $name:ident [ $row:literal ] [ $col:literal ], $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ident!($module, $name).into(), -// access_type: AccessType::Matrix($row, $col), -// offset: 0, -// ty: Some($ty), -// }) -// }; -// -// ($name:ident [ $idx:literal ], $offset:literal) => { -// ScalarExpr::SymbolAccess(SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Index($idx), -// $offset, -// )) -// }; -// -// ($name:ident [ $idx:literal ], $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Local(ident!($name)), -// access_type: AccessType::Index($idx), -// offset: 0, -// ty: Some($ty), -// }) -// }; -// -// ($name:ident [ $idx:literal ], $offset:literal, $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Local(ident!($name)), -// access_type: AccessType::Index($idx), -// offset: $offset, -// ty: Some($ty), -// }) -// }; -// -// ($name:literal [ $idx:literal ], $offset:literal) => { -// ScalarExpr::SymbolAccess(SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Index($idx), -// $offset, -// )) -// }; -//} -// -//macro_rules! expr { -// ($expr:expr) => { -// Expr::try_from($expr).unwrap() -// }; -//} -// -//macro_rules! slice { -// ($name:ident, $range:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Unresolved(NamespacedIdentifier::Binding(ident!($name))), -// access_type: AccessType::Slice($range), -// offset: 0, -// ty: None, -// }) -// }; -// -// ($name:ident, $range:expr, $ty:expr) => { -// ScalarExpr::SymbolAccess(SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Local(ident!($name)), -// access_type: AccessType::Slice($range), -// offset: 0, -// ty: Some($ty), -// }) -// }; -//} -// -//macro_rules! bounded_access { -// ($name:ident, $bound:expr) => { -// ScalarExpr::BoundedSymbolAccess(BoundedSymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Default, -// 0, -// ), -// $bound, -// )) -// }; -// -// ($name:ident, $bound:expr, $ty:expr) => { -// ScalarExpr::BoundedSymbolAccess(BoundedSymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Local(ident!($name)), -// access_type: AccessType::Default, -// offset: 0, -// ty: Some($ty), -// }, -// $bound, -// )) -// }; -// -// ($name:ident [ $idx:literal ], $bound:expr) => { -// ScalarExpr::BoundedSymbolAccess(BoundedSymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// SymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// ident!($name), -// AccessType::Index($idx), -// 0, -// ), -// $bound, -// )) -// }; -// -// ($name:ident [ $idx:literal ], $bound:expr, $ty:expr) => { -// ScalarExpr::BoundedSymbolAccess(BoundedSymbolAccess::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// SymbolAccess { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// name: ResolvableIdentifier::Local(ident!($name)), -// access_type: AccessType::Index($idx), -// offset: 0, -// ty: Some($ty), -// }, -// $bound, -// )) -// }; -//} -// -//macro_rules! int { -// ($value:literal) => { -// ScalarExpr::Const(miden_diagnostics::Span::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// $value, -// )) -// }; -// -// ($value:expr) => { -// ScalarExpr::Const(miden_diagnostics::Span::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// $value, -// )) -// }; -//} -// -//macro_rules! call { -// ($callee:ident ($($param:expr),+)) => { -// ScalarExpr::Call(Call::new(miden_diagnostics::SourceSpan::UNKNOWN, ident!($callee), vec![$($param),+])) -// }; -// -// ($module:ident :: $callee:ident ($($param:expr),+)) => { -// ScalarExpr::Call(Call { -// span: miden_diagnostics::SourceSpan::UNKNOWN, -// callee: ResolvableIdentifier::Resolved(function_ident!($module, $callee)), -// args: vec![$($param),+], -// ty: None, -// }) -// } -//} -// -//macro_rules! trace_segment { -// ($idx:literal, $name:literal, [$(($binding_name:ident, $binding_size:literal)),*]) => { -// TraceSegment::new(miden_diagnostics::SourceSpan::UNKNOWN, $idx, ident!($name), vec![ -// $(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, (ident!($binding_name), $binding_size))),* -// ]) -// } -//} -// -//macro_rules! random_values { -// ($name:literal, $size:literal) => { -// RandomValues::with_size(miden_diagnostics::SourceSpan::UNKNOWN, ident!($name), $size) -// }; -// -// ($name:literal, [$(($binding_name:ident, $binding_size:literal)),*]) => { -// RandomValues::new(miden_diagnostics::SourceSpan::UNKNOWN, ident!($name), vec![ -// $(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, (ident!($binding_name), $binding_size))),* -// ]) -// } -//} -// -//macro_rules! constant { -// ($name:ident = $value:literal) => { -// Constant::new( -// SourceSpan::UNKNOWN, -// ident!($name), -// ConstantExpr::Scalar($value), -// ) -// }; -// -// ($name:ident = [$($value:literal),+]) => { -// Constant::new(SourceSpan::UNKNOWN, ident!($name), ConstantExpr::Vector(vec![$($value),+])) -// }; -// -// ($name:ident = [$([$($value:literal),+]),+]) => { -// Constant::new(SourceSpan::UNKNOWN, ident!($name), ConstantExpr::Matrix(vec![$(vec![$($value),+]),+])) -// }; -//} -// -//macro_rules! vector { -// ($($value:literal),*) => { -// Expr::Const(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, ConstantExpr::Vector(vec![$($value),*]))) -// }; -// -// ($($value:expr),*) => { -// Expr::Vector(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, vec![$(expr!($value)),*])) -// } -//} -// -//macro_rules! matrix { -// ($([$($value:expr),+]),+) => { -// Expr::Matrix(miden_diagnostics::Span::new(miden_diagnostics::SourceSpan::UNKNOWN, vec![$(vec![$($value),+]),+])) -// }; -//} -// -//macro_rules! let_ { -// ($name:ident = $value:expr => $($body:expr),+) => { -// Statement::Let(Let::new(miden_diagnostics::SourceSpan::UNKNOWN, ident!($name), $value, vec![$($body),+])) -// }; -// -// ($name:literal = $value:expr => $($body:expr),+) => { -// Statement::Let(Let::new(miden_diagnostics::SourceSpan::UNKNOWN, ident!($name), $value, vec![$($body),+])) -// }; -//} -// -//macro_rules! enforce { -// ($expr:expr) => { -// Statement::Enforce($expr) -// }; -// -// ($expr:expr, when $selector:expr) => { -// Statement::EnforceIf($expr, $selector) -// }; -//} -// -//macro_rules! enforce_all { -// ($expr:expr) => { -// Statement::EnforceAll($expr) -// }; -//} -// -//macro_rules! lc { -// (($(($binding:ident, $iterable:expr)),+) => $body:expr) => {{ -// let context = vec![ -// $( -// (ident!($binding), $iterable) -// ),+ -// ]; -// ListComprehension::new(miden_diagnostics::SourceSpan::UNKNOWN, $body, context, None) -// }}; -// -// (($(($binding:literal, $iterable:expr)),+) => $body:expr) => {{ -// let context = vec![ -// $( -// (ident!($binding), $iterable) -// ),+ -// ]; -// ListComprehension::new(miden_diagnostics::SourceSpan::UNKNOWN, $body, context, None) -// }}; -// -// (($(($binding:ident, $iterable:expr)),*) => $body:expr, when $selector:expr) => {{ -// let context = vec![ -// $( -// (ident!($binding), $iterable) -// ),+ -// ]; -// ListComprehension::new(miden_diagnostics::SourceSpan::UNKNOWN, $body, context, Some($selector)) -// }}; -// -// (($(($binding:literal, $iterable:expr)),*) => $body:expr, when $selector:expr) => {{ -// let context = vec![ -// $( -// (ident!($binding), $iterable) -// ),+ -// ]; -// ListComprehension::new(miden_diagnostics::SourceSpan::UNKNOWN, $body, context, Some($selector)) -// }}; -//} -// -//macro_rules! range { -// ($range:expr) => { -// Expr::Range(miden_diagnostics::Span::new(SourceSpan::UNKNOWN, $range)) -// }; -//} -// -//macro_rules! and { -// ($lhs:expr, $rhs:expr) => { -// mul!($lhs, $rhs) -// }; -//} -// -//macro_rules! or { -// ($lhs:expr, $rhs:expr) => {{ -// sub!(add!($lhs, $rhs), mul!($lhs, $rhs)) -// }}; -//} -// -//macro_rules! not { -// ($rhs:expr) => { -// sub!(int!(1), $rhs) -// }; -//} -// -//macro_rules! eq { -// ($lhs:expr, $rhs:expr) => { -// ScalarExpr::Binary(BinaryExpr::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// BinaryOp::Eq, -// $lhs, -// $rhs, -// )) -// }; -//} -// -//macro_rules! add { -// ($lhs:expr, $rhs:expr) => { -// ScalarExpr::Binary(BinaryExpr::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// BinaryOp::Add, -// $lhs, -// $rhs, -// )) -// }; -//} -// -//macro_rules! sub { -// ($lhs:expr, $rhs:expr) => { -// ScalarExpr::Binary(BinaryExpr::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// BinaryOp::Sub, -// $lhs, -// $rhs, -// )) -// }; -//} -// -//macro_rules! mul { -// ($lhs:expr, $rhs:expr) => { -// ScalarExpr::Binary(BinaryExpr::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// BinaryOp::Mul, -// $lhs, -// $rhs, -// )) -// }; -//} -// -//macro_rules! exp { -// ($lhs:expr, $rhs:expr) => { -// ScalarExpr::Binary(BinaryExpr::new( -// miden_diagnostics::SourceSpan::UNKNOWN, -// BinaryOp::Exp, -// $lhs, -// $rhs, -// )) -// }; -//} -// -//macro_rules! import_all { -// ($module:ident) => { -// Import::All { -// module: ident!($module), -// } -// }; -//} -// -//macro_rules! import { -// ($module:ident, $item:ident) => {{ -// let mut items: std::collections::HashSet = std::collections::HashSet::default(); -// items.insert(ident!($item)); -// Import::Partial { -// module: ident!($module), -// items, -// } -// }}; -//} - // FULL MIDEN IR FILE // ================================================================================================