diff --git a/Cargo.lock b/Cargo.lock index c5c79e49..3a426243 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" @@ -819,12 +897,16 @@ dependencies = [ "anyhow", "cranelift-entity", "intrusive-collections", + "lalrpop", + "lalrpop-util", "miden-assembly", "miden-diagnostics", "miden-hir-symbol", "miden-hir-type", + "miden-parsing", "paste", "petgraph", + "pretty_assertions", "rustc-hash", "smallvec", "thiserror", @@ -883,6 +965,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" @@ -906,6 +998,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 +1100,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 +1339,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 +1460,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 +1527,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/frontend-wasm/src/code_translator/tests.rs b/frontend-wasm/src/code_translator/tests.rs index 08be2e35..60c2f077 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/dlmalloc.mir b/frontend-wasm/tests/expected/dlmalloc.mir index 042965f7..c131e848 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 } +} diff --git a/frontend-wasm/tests/expected/signed_arith.mir b/frontend-wasm/tests/expected/signed_arith.mir index d4566efd..7f16896c 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 03655d92..5f9222b0 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 e03510e6..82b2b1a8 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-transform/src/inline_blocks.rs b/hir-transform/src/inline_blocks.rs index f77287bd..1d7c55d0 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 1d09a73c..b73e309b 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 aca8d1dc..961ddcee 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/Cargo.toml b/hir/Cargo.toml index e9f0de04..2ecaefa8 100644 --- a/hir/Cargo.toml +++ b/hir/Cargo.toml @@ -10,16 +10,22 @@ 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 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/build.rs b/hir/build.rs new file mode 100644 index 00000000..23c7d3f8 --- /dev/null +++ b/hir/build.rs @@ -0,0 +1,5 @@ +extern crate lalrpop; + +fn main() { + lalrpop::process_root().unwrap(); +} diff --git a/hir/src/instruction.rs b/hir/src/instruction.rs index 8c74e0b2..a7b5fd9d 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 f7a43ac9..f6fcfd89 100644 --- a/hir/src/lib.rs +++ b/hir/src/lib.rs @@ -1,4 +1,8 @@ #![deny(warnings)] +pub 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 new file mode 100644 index 00000000..e15ec137 --- /dev/null +++ b/hir/src/parser/ast/block.rs @@ -0,0 +1,102 @@ +use super::*; +use crate::{Ident, Type}; + +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, +} +impl Label { + pub fn new(name: Ident) -> 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 +#[derive(PartialEq, Debug)] +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 +#[derive(PartialEq, Debug)] +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.is_empty() { + 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, Debug)] +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 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)?; + for inst in self.instructions.iter() { + writeln!(f, "{}{}", INDENT, inst)?; + } + Ok(()) + } +} diff --git a/hir/src/parser/ast/functions.rs b/hir/src/parser/ast/functions.rs new file mode 100644 index 00000000..83a42101 --- /dev/null +++ b/hir/src/parser/ast/functions.rs @@ -0,0 +1,174 @@ +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, + /// Public visibility + Public, +} + +/// 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, + /// The bit extension for the parameter + pub extension: ArgumentExtension, + /// The type of the parameter + pub ty: Type, +} +impl FunctionParameter { + pub fn new(purpose: ArgumentPurpose, extension: ArgumentExtension, ty: Type) -> Self { + Self { + purpose, + extension, + ty, + } + } +} +impl fmt::Display for FunctionParameter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.purpose { + ArgumentPurpose::Default => Ok(()), + ArgumentPurpose::StructReturn => f.write_str("sret "), + }?; + match self.extension { + ArgumentExtension::None => Ok(()), + ArgumentExtension::Zext => f.write_str("zext "), + ArgumentExtension::Sext => f.write_str("sext "), + }?; + write!(f, "{}", self.ty) + } +} + +/// A single return value from a function. +#[derive(PartialEq, Debug)] +pub struct FunctionReturn { + /// The bit extension for the parameter + pub extension: ArgumentExtension, + /// The type of the parameter + pub ty: Type, +} +impl FunctionReturn { + 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 { + ArgumentExtension::None => Ok(()), + ArgumentExtension::Zext => f.write_str("zext "), + ArgumentExtension::Sext => f.write_str("sext "), + }?; + write!(f, "{}", self.ty) + } +} + +/// Represents the type signature of a function +#[derive(Spanned, Debug)] +pub struct FunctionSignature { + #[span] + pub span: SourceSpan, + pub visibility: Visibility, + pub call_convention: CallConv, + pub name: FunctionIdent, + pub params: Vec, + pub returns: Vec, +} +impl FunctionSignature { + pub fn new( + span: SourceSpan, + visibility: Visibility, + call_convention: CallConv, + name: FunctionIdent, + params: Vec, + returns: Vec, + ) -> Self { + Self { + span, + visibility, + call_convention, + name, + params, + returns, + } + } +} +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 { + Visibility::Private => Ok(()), + Visibility::Public => f.write_str("pub "), + }?; + match self.call_convention { + 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() { + 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, Debug)] +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 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)?; + f.write_str("{{\n")?; + for block in self.blocks.iter() { + write!(f, "{}", block)?; + } + f.write_str("}}\n") + } +} diff --git a/hir/src/parser/ast/globals.rs b/hir/src/parser/ast/globals.rs new file mode 100644 index 00000000..d048b30c --- /dev/null +++ b/hir/src/parser/ast/globals.rs @@ -0,0 +1,79 @@ +use std::fmt; + +use miden_diagnostics::{SourceSpan, Spanned}; + +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; + +/// 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, Debug)] +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, + name, + ty, + linkage, + init: None, + } + } + + pub fn with_init(&mut self, init: GlobalVarInitializer) { + 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)?; + if self.init.is_some() { + write!(f, "= {}", self.init.as_ref().unwrap())?; + } + Ok(()) + } +} diff --git a/hir/src/parser/ast/instruction.rs b/hir/src/parser/ast/instruction.rs new file mode 100644 index 00000000..b23ee8af --- /dev/null +++ b/hir/src/parser/ast/instruction.rs @@ -0,0 +1,611 @@ +use super::*; +use crate::{FunctionIdent, Ident, Overflow, Type}; + +/// Represents a value in Miden IR. +/// +/// 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, +} +impl Value { + pub fn new(name: Ident) -> 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 +#[derive(PartialEq, Debug)] +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, Debug)] +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 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() { + 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 +#[derive(PartialEq, Debug)] +pub enum Operation { + BinaryOp(BinaryOpCode, Value, Value), + BinaryImmOp(BinaryImmOpCode, Value, Immediate), + UnaryOp(UnaryOpCode, Value), + UnaryImmOp(UnaryImmOpCode, Immediate), + ReturnOp(Vec), + CallOp(CallOp, FunctionIdent, 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 +#[derive(PartialEq, Debug)] +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 +#[derive(PartialEq, Debug)] +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 +#[derive(PartialEq, Debug)] +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 +#[derive(PartialEq, Debug)] +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 +#[derive(PartialEq, Debug)] +pub enum UnaryImmOpCode { + I1, + I8, + I16, + I32, + I64, + 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::Felt => f.write_str("felt"), + Self::F64 => f.write_str("f64"), + } + } +} + +/// Used to distinguish between primary operations +#[derive(PartialEq, Debug)] +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. +#[derive(PartialEq, Debug)] +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 +#[derive(PartialEq, Debug)] +pub enum GlobalValueOpNested { + Symbol(Ident, 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 +#[derive(PartialEq, Debug)] +pub enum GlobalValueOp { + Symbol(Ident, 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) + } + } + } +} + +/// The destination of a branch/jump +#[derive(PartialEq, Debug)] +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.is_empty() { + 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 +#[derive(PartialEq, Debug)] +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/src/parser/ast/mod.rs b/hir/src/parser/ast/mod.rs new file mode 100644 index 00000000..6aa1a6c5 --- /dev/null +++ b/hir/src/parser/ast/mod.rs @@ -0,0 +1,92 @@ +mod block; +mod functions; +mod globals; +mod instruction; + +pub use self::block::*; +pub use self::functions::*; +pub use self::globals::*; +pub use self::instruction::*; + +use std::fmt; + +use miden_diagnostics::{SourceSpan, Spanned}; + +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, Debug, 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, Debug)] +pub struct Module { + #[span] + pub span: SourceSpan, + pub name: ModuleId, + pub ty: ModuleType, + pub global_vars: Vec, + 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, + global_vars: Vec, + functions: Vec, + externals: Vec, + ) -> Self { + Self { + span, + name, + ty, + functions, + externals, + global_vars, + } + } +} +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)?; + for gvar in self.global_vars.iter() { + writeln!(f, "{}", gvar)?; + } + for func in self.functions.iter() { + writeln!(f, "{}", func)?; + } + for ext in self.externals.iter() { + writeln!(f, "{};", ext)?; + } + Ok(()) + } +} diff --git a/hir/src/parser/lexer/mod.rs b/hir/src/parser/lexer/mod.rs new file mode 100644 index 00000000..83c63e90 --- /dev/null +++ b/hir/src/parser/lexer/mod.rs @@ -0,0 +1,985 @@ +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), + /// 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 + 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 a function. + 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, + F64, + Felt, + Mut, + + // PUNCTUATION + // -------------------------------------------------------------------------------------------- + DoubleQuote, + Colon, + 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, + "fn" => Self::Fn, + "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, + "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; + } + } + Self::FuncIdent(i) => { + if let Self::FuncIdent(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::FuncIdent(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::F64 => write!(f, "f64"), + Self::Felt => write!(f, "felt"), + Self::Mut => write!(f, "mut"), + Self::DoubleQuote => write!(f, "\""), + Self::Colon => 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), + ':' => pop!(self, Token::Colon), + ';' => pop!(self, Token::Semicolon), + '"' => 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()); + + if self.skip_ident() { + Token::FuncIdent(Symbol::intern(self.slice())) + } else { + Token::from_keyword_or_ident(self.slice()) + } + } + + #[inline] + fn lex_identifier(&mut self) -> Token { + let c = self.pop(); + debug_assert!(c.is_ascii_alphabetic()); + + if self.skip_ident() { + Token::FuncIdent(Symbol::intern(self.slice())) + } else { + Token::Ident(Symbol::intern(self.slice())) + } + } + + // 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] + 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/src/parser/mod.rs b/hir/src/parser/mod.rs new file mode 100644 index 00000000..38fd96f8 --- /dev/null +++ b/hir/src/parser/mod.rs @@ -0,0 +1,105 @@ +pub mod ast; +mod lexer; +mod parser; + +pub use self::parser::{ParseError, Parser}; +use super::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. +#[allow(dead_code)] +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. +#[allow(dead_code)] +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/src/parser/parser/grammar.lalrpop b/hir/src/parser/parser/grammar.lalrpop new file mode 100644 index 00000000..9e6ddfba --- /dev/null +++ b/hir/src/parser/parser/grammar.lalrpop @@ -0,0 +1,739 @@ +use std::sync::Arc; +use std::str::FromStr; + +use miden_diagnostics::{CodeMap, DiagnosticsHandler}; + +use crate::{AddressSpace, ArgumentPurpose, ArgumentExtension, CallConv, FunctionIdent, Ident, Linkage, Overflow, StructType, Type, }; +use crate::parser::{ + 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 + } +}; + +// Comma-delimited, possibly empty, possibly with a trailing comma +CommaOpt: Vec = { + ",")*> => { + let mut v = v; + v.extend(e); + v + } +}; + +// AST NODE +// ================================================================================================ + +pub Module: Module = { + "kernel" => { + Module::new(span!(l, r), ModuleType::Kernel, name, globals, functions, externals) + }, + "module" => { + Module::new(span!(l, r), ModuleType::Module, name, globals, 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, + "f64" => Type::F64, + "felt" => Type::Felt, + "*" "mut" => Type::Ptr(Box::new(inner)), + "&" "mut" => Type::NativePtr(Box::new(inner), AddressSpace::Unknown), + "{" > "}" => Type::Struct(StructType::new(field_types)), + "[" ";" "]" => Type::Array(Box::new(inner), usize::try_from(length).unwrap()), +} + +// FUNCTIONS +// ============================================================================================== + +ExternalFunction: FunctionSignature = { + ";" => signature +} + +CallConvention: CallConv = { + "cc" "(" "fast" ")" => CallConv::Fast, + "cc" "(" "kernel" ")" => CallConv::Kernel, +} + +ParamPurpose: ArgumentPurpose = { + => ArgumentPurpose::Default, + "sret" => ArgumentPurpose::StructReturn, +} + +ParamExtension: ArgumentExtension = { + "zext" => ArgumentExtension::Zext, + "sext" => ArgumentExtension::Sext, +} + +FunctionReturn: FunctionReturn = { + => { + let ext = if let Some(e) = extension { e } else { ArgumentExtension::None }; + FunctionReturn::new(ext, ty) + } +} + +FunctionReturnSignature: Vec = { + "->" > => returns +} + +FunctionParam: FunctionParameter = { + => { + let ext = if let Some(e) = extension { e } else { ArgumentExtension::None }; + FunctionParameter::new(purpose, ext, ty) + } +} + +FunctionParams: Vec = { + "(" > ")" => params, +} + +FunctionSignature: FunctionSignature = { + "pub" "fn" => { + 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 { CallConv::SystemV }; + 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" "." "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) + }, + "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: Ident = { + => Ident::new(name, span!(l, r)) +} + +Value: Value = { + => Value::new(id) +} + +FunctionIdentifier: FunctionIdent = { + => FunctionIdent::from_str(name.as_str()).unwrap() +} + + + +// LEXER +// ================================================================================================ + +extern { + type Error = ParseError; + type Location = miden_diagnostics::SourceIndex; + + enum Token { + identifier => Token::Ident(), + func_identifier => Token::FuncIdent(), + 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, + "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::Semicolon, + "," => Token::Comma, + "[" => Token::LBracket, + "]" => Token::RBracket, + "(" => Token::LParen, + ")" => Token::RParen, + "{" => Token::LBrace, + "}" => Token::RBrace, + "." => Token::Dot, + "@" => Token::At, + } +} diff --git a/hir/src/parser/parser/mod.rs b/hir/src/parser/parser/mod.rs new file mode 100644 index 00000000..24b5514f --- /dev/null +++ b/hir/src/parser/parser/mod.rs @@ -0,0 +1,217 @@ +// 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/parser/grammar.rs" +); + +use std::sync::Arc; + +use miden_diagnostics::{ + CodeMap, Diagnostic, DiagnosticsHandler, Label, SourceIndex, SourceSpan, ToDiagnostic, +}; +use miden_parsing::{Scanner, Source}; + +use crate::parser::{ + 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::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()), + } + } +} + +#[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 00000000..797669a8 --- /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 00000000..04ec48e4 --- /dev/null +++ b/hir/src/parser/parser/tests/mod.rs @@ -0,0 +1,177 @@ +use crate::parser::ast::*; +use crate::{ArgumentExtension, ArgumentPurpose, CallConv, FunctionIdent, Ident, Linkage, Overflow, StructType, Type}; + +mod utils; +use self::utils::ParseTest; + +macro_rules! ident { + ($name:ident) => { + Ident::new( + crate::Symbol::intern(stringify!($name)), + miden_diagnostics::SourceSpan::UNKNOWN, + ) + }; +} + +macro_rules! function_ident { + ($module:ident, $name:ident) => { + FunctionIdent { + module: ident!($module), + function: ident!($name), + } + }; +} + +// 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 00000000..e406fb73 --- /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), + } + } +} diff --git a/hir/src/write.rs b/hir/src/write.rs index 30b59464..4b4033f2 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,13 @@ 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))) @@ -187,21 +195,11 @@ fn write_operands( write!(w, ", {}", else_dest.0)?; 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..]) + write!(w, " {}", destination)?; + write_block_args(w, args.as_slice(pool)) } Instruction::Switch(Switch { arg, arms, default, ..