From 2893855b7f0b71d5cb858d2fdfe780b2098ca878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Tue, 13 Jun 2023 19:30:24 +0200 Subject: [PATCH] chore(brillig): master into brillig main (#1663) * fix(ssa refactor): resolve replaced value ids for printing (#1535) * fix(ssa refactor): resolve replaced value ids for printing * fix(ssa refactor): Expand PR #1535 to resolve ValueIds in all SSA passes (#1642) * Expand PR * chore(ssa refactor): more value id resolving * chore(ssa refactor): another value id resolve --------- Co-authored-by: Joss --------- Co-authored-by: jfecher * chore(ssa refactor): enable_side_effects instruction (#1547) * chore(ssa refactor): enable_side_effects instruction * chore(ssa refactor): fix and document enable_side_effects insertions * chore(ssa refactor): rm comments * fix(ssa refactor): redundant EnableSideEffects * chore(ssa refactor): cp working tests (#1619) * chore(ssa gen): ssa gen truncate instruction * chore(ssa refactor): max bit size for subtract * Update crates/noirc_evaluator/src/ssa_refactor/ssa_gen/context.rs Co-authored-by: jfecher * chore(ssa refactor): truncate shift left * chore(ssa refactor): Add integer modulus when truncating subtraction * chore(ssa refactor): clippy * chore(ssa refactor): fix left shift max bit size * chore(ssa refactor): cp xor test * chore(ssa refactor): cp working tests * chore(ssa refactor): more working tests * chore(ssa refactor): cp working test --------- Co-authored-by: kevaundray Co-authored-by: jfecher * chore(ssa refactor): Remove unit values from SSA IR (#1646) * Remove unit values * Fix test * Fix comment * chore: Upgrade codespan dependencies (#1647) * chore(ssa refactor): Implement dead instruction elimination pass (#1595) * Add dead instruction elimination pass * Enable the pass * chore(ssa refactor): simple mut test * chore(ssa refactor): fixup and add doc comments * chore(ssa refactor): post merge fix --------- Co-authored-by: Joss * chore(brillig): Update acvm dependency (#1653) chore: update acvm dep * refactor: remove unused assign --------- Co-authored-by: joss-aztec <94053499+joss-aztec@users.noreply.github.com> Co-authored-by: jfecher Co-authored-by: kevaundray Co-authored-by: Blaine Bublitz Co-authored-by: Joss --- Cargo.lock | 28 +- Cargo.toml | 6 +- crates/fm/src/file_map.rs | 2 +- .../test_data_ssa_refactor/assert/Nargo.toml | 5 + .../test_data_ssa_refactor/assert/Prover.toml | 1 + .../test_data_ssa_refactor/assert/src/main.nr | 3 + .../test_data_ssa_refactor/bit_and/Nargo.toml | 5 + .../bit_and/Prover.toml | 2 + .../bit_and/src/main.nr | 18 ++ .../bit_shifts_comptime/Nargo.toml | 5 + .../bit_shifts_comptime/Prover.toml | 1 + .../bit_shifts_comptime/src/main.nr | 13 + .../bool_not/Nargo.toml | 7 + .../bool_not/Prover.toml | 1 + .../bool_not/src/main.nr | 5 + .../test_data_ssa_refactor/bool_or/Nargo.toml | 7 + .../bool_or/Prover.toml | 2 + .../bool_or/src/main.nr | 7 + .../brillig_oracle/src/main.nr | 4 +- .../cast_bool/Nargo.toml | 7 + .../cast_bool/Prover.toml | 2 + .../cast_bool/src/main.nr | 6 + .../comptime_array_access/Nargo.toml | 5 + .../comptime_array_access/Prover.toml | 1 + .../comptime_array_access/src/main.nr | 17 + .../comptime_recursion_regression/Nargo.toml | 5 + .../comptime_recursion_regression/Prover.toml | 2 + .../comptime_recursion_regression/src/main.nr | 4 + .../contracts/Nargo.toml | 5 + .../contracts/Prover.toml | 2 + .../contracts/src/main.nr | 8 + .../hash_to_field/Nargo.toml | 5 + .../hash_to_field/Prover.toml | 1 + .../hash_to_field/src/main.nr | 5 + .../main_bool_arg/Nargo.toml | 6 + .../main_bool_arg/Prover.toml | 2 + .../main_bool_arg/src/main.nr | 8 + .../main_return/Nargo.toml | 6 + .../main_return/Prover.toml | 1 + .../main_return/src/main.nr | 3 + .../test_data_ssa_refactor/modules/Nargo.toml | 5 + .../modules/Prover.toml | 2 + .../test_data_ssa_refactor/modules/src/foo.nr | 3 + .../modules/src/main.nr | 14 + .../modules_more/Nargo.toml | 5 + .../modules_more/Prover.toml | 4 + .../modules_more/src/foo.nr | 5 + .../modules_more/src/foo/bar.nr | 3 + .../modules_more/src/main.nr | 6 + .../test_data_ssa_refactor/modulus/Nargo.toml | 5 + .../modulus/Prover.toml | 290 ++++++++++++++++++ .../modulus/src/main.nr | 27 ++ .../test_data_ssa_refactor/pred_eq/Nargo.toml | 7 + .../pred_eq/Prover.toml | 2 + .../pred_eq/src/main.nr | 6 + .../simple_mut/Nargo.toml | 5 + .../simple_mut/Prover.toml | 1 + .../simple_mut/src/main.nr | 7 + .../test_data_ssa_refactor/struct/Nargo.toml | 7 + .../test_data_ssa_refactor/struct/Prover.toml | 2 + .../test_data_ssa_refactor/struct/src/main.nr | 77 +++++ .../struct_fields_ordering/Nargo.toml | 5 + .../struct_fields_ordering/Prover.toml | 3 + .../struct_fields_ordering/src/main.nr | 14 + .../submodules/Nargo.toml | 7 + .../submodules/Prover.toml | 2 + .../submodules/src/main.nr | 17 + .../test_data_ssa_refactor/xor/Nargo.toml | 5 + .../test_data_ssa_refactor/xor/Prover.toml | 2 + .../test_data_ssa_refactor/xor/src/main.nr | 5 + .../src/brillig/brillig_gen.rs | 1 - crates/noirc_evaluator/src/ssa_refactor.rs | 2 + .../acir_gen/acir_ir/acir_variable.rs | 11 +- .../acir_gen/acir_ir/generated_acir.rs | 3 +- .../src/ssa_refactor/acir_gen/mod.rs | 37 +-- .../src/ssa_refactor/ir/dfg.rs | 28 +- .../src/ssa_refactor/ir/instruction.rs | 85 ++++- .../src/ssa_refactor/ir/printer.rs | 4 + .../src/ssa_refactor/ir/types.rs | 4 - .../src/ssa_refactor/opt/constant_folding.rs | 11 +- .../src/ssa_refactor/opt/die.rs | 194 ++++++++++++ .../src/ssa_refactor/opt/flatten_cfg.rs | 158 +++++++--- .../src/ssa_refactor/opt/inlining.rs | 5 +- .../src/ssa_refactor/opt/mem2reg.rs | 9 +- .../src/ssa_refactor/opt/mod.rs | 1 + .../src/ssa_refactor/opt/unrolling.rs | 3 +- .../src/ssa_refactor/ssa_gen/context.rs | 10 +- .../src/ssa_refactor/ssa_gen/mod.rs | 14 +- .../src/ssa_refactor/ssa_gen/value.rs | 5 + 89 files changed, 1214 insertions(+), 137 deletions(-) create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/assert/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/assert/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/assert/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/contracts/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/contracts/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/contracts/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/main_return/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/main_return/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/main_return/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modules/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modules/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modules/src/foo.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modules/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/foo.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/foo/bar.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modulus/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modulus/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/modulus/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/struct/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/struct/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/struct/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/submodules/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/submodules/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/submodules/src/main.nr create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/xor/Nargo.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/xor/Prover.toml create mode 100644 crates/nargo_cli/tests/test_data_ssa_refactor/xor/src/main.nr create mode 100644 crates/noirc_evaluator/src/ssa_refactor/opt/die.rs diff --git a/Cargo.lock b/Cargo.lock index 86d0a9cf8fc..0e703f23b7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "acir" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2d2b80c4e6e0c6f2b5d45693925f6eac1e6fcf9a908aad70158e58b9ed18b0" +checksum = "a46e07ed303f80970f1d9decc1e8d8265ab3766bd51239a488fcd34c7224ad15" dependencies = [ "acir_field", "brillig_vm", @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "acir_field" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c984be877eae94755269391ebde859d65416c7aa7955badc3338464dbbdd1f38" +checksum = "bbfc12f808a783f3d5d38cea06a06a196924a0741c78c7ac32ee45542ca474c3" dependencies = [ "ark-bn254", "ark-ff", @@ -32,9 +32,9 @@ dependencies = [ [[package]] name = "acvm" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31caccd81f7ea1ce5a9417ff283da0f4932ee28d63f6554049de03fe3d69d77" +checksum = "74369333d147335a74871483868385ec8d6c89721693f71cb76f85515d89ef37" dependencies = [ "acir", "acvm_stdlib", @@ -71,9 +71,9 @@ dependencies = [ [[package]] name = "acvm_stdlib" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42f48d5c9ecfb1662ec7cbcf337fb4bb9323daf6e0168574431a9ec29684beb" +checksum = "4a1a417fb146c74b4674334a1512ebc1b81d972bf0f38dd843117f449ef6e72f" dependencies = [ "acir", ] @@ -514,9 +514,9 @@ dependencies = [ [[package]] name = "brillig_vm" -version = "0.14.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e59215d1d45d136bcba2f1bbf18cf6c93477375afb851c4afaf8d7aa21b27" +checksum = "2a655a12c64f9a8e3cf388a5577b35cec22c87cfc3156bfead33de0c3778cf37" dependencies = [ "acir_field", "num-bigint", @@ -692,18 +692,18 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "codespan" -version = "0.9.5" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ebaf6bb6a863ad6aa3a18729e9710c53d75df03306714d9cc1f7357a00cd789" +checksum = "3362992a0d9f1dd7c3d0e89e0ab2bb540b7a95fea8cd798090e758fda2899b5e" dependencies = [ "codespan-reporting", ] [[package]] name = "codespan-reporting" -version = "0.9.5" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0762455306b1ed42bc651ef6a2197aabda5e1d4a43c34d5eab5c1a3634e81d" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" dependencies = [ "termcolor", "unicode-width", diff --git a/Cargo.toml b/Cargo.toml index 72469ca2e20..929c4958b93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ edition = "2021" rust-version = "1.66" [workspace.dependencies] -acvm = "=0.14.3" +acvm = "=0.14.4" arena = { path = "crates/arena" } fm = { path = "crates/fm" } iter-extended = { path = "crates/iter-extended" } @@ -40,8 +40,8 @@ noir_wasm = { path = "crates/wasm" } cfg-if = "1.0.0" clap = { version = "4.1.4", features = ["derive"] } -codespan = "0.9.5" -codespan-reporting = "0.9.5" +codespan = "0.11.1" +codespan-reporting = "0.11.1" chumsky = { git = "https://github.com/jfecher/chumsky", rev = "ad9d312" } dirs = "4" serde = { version = "1.0.136", features = ["derive"] } diff --git a/crates/fm/src/file_map.rs b/crates/fm/src/file_map.rs index 150451df9ba..4dbfbece0e0 100644 --- a/crates/fm/src/file_map.rs +++ b/crates/fm/src/file_map.rs @@ -62,7 +62,7 @@ impl FileMap { FileId(file_id) } pub fn get_file(&self, file_id: FileId) -> Option { - self.0.get(file_id.0).map(File) + self.0.get(file_id.0).map(File).ok() } } diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/assert/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/assert/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/assert/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/assert/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/assert/Prover.toml new file mode 100644 index 00000000000..4dd6b405159 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/assert/Prover.toml @@ -0,0 +1 @@ +x = "1" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/assert/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/assert/src/main.nr new file mode 100644 index 00000000000..00e94414c0b --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/assert/src/main.nr @@ -0,0 +1,3 @@ +fn main(x: Field) { + assert(x == 1); +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/Prover.toml new file mode 100644 index 00000000000..40ce2b0bc27 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/Prover.toml @@ -0,0 +1,2 @@ +x = "0x00" +y = "0x10" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/src/main.nr new file mode 100644 index 00000000000..f4805960a33 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_and/src/main.nr @@ -0,0 +1,18 @@ +// You can only do bit operations with integers. +// (Kobi/Daira/Circom/#37) https://github.com/iden3/circom/issues/37 +fn main(x : Field, y : Field) { + let x_as_u8 = x as u8; + let y_as_u8 = y as u8; + + assert((x_as_u8 & y_as_u8) == x_as_u8); + + //bitwise and with 1 bit: + let flag = (x == 0) & (y == 16); + assert(flag); + + //bitwise and with odd bits: + let x_as_u11 = x as u11; + let y_as_u11 = y as u11; + assert((x_as_u11 & y_as_u11) == x_as_u11); +} + diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/Prover.toml new file mode 100644 index 00000000000..cfd62c406cb --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/Prover.toml @@ -0,0 +1 @@ +x = 64 diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/src/main.nr new file mode 100644 index 00000000000..c1c6890febb --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bit_shifts_comptime/src/main.nr @@ -0,0 +1,13 @@ +fn main(x: u64) { + let two: u64 = 2; + let three: u64 = 3; + + // comptime shifts on comptime values + assert(two << 2 == 8); + assert((two << 3) / 8 == two); + assert((three >> 1) == 1); + + // comptime shifts on runtime values + assert(x << 1 == 128); + assert(x >> 2 == 16); +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/Nargo.toml new file mode 100644 index 00000000000..d9434868157 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/Nargo.toml @@ -0,0 +1,7 @@ + + [package] + authors = [""] + compiler_version = "0.1" + + [dependencies] + \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/Prover.toml new file mode 100644 index 00000000000..4dd6b405159 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/Prover.toml @@ -0,0 +1 @@ +x = "1" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/src/main.nr new file mode 100644 index 00000000000..d6b4d7a9fad --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_not/src/main.nr @@ -0,0 +1,5 @@ +use dep::std; +fn main(x: u1) { + assert(!x == 0); +} + diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/Nargo.toml new file mode 100644 index 00000000000..d9434868157 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/Nargo.toml @@ -0,0 +1,7 @@ + + [package] + authors = [""] + compiler_version = "0.1" + + [dependencies] + \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/Prover.toml new file mode 100644 index 00000000000..a0397e89477 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/Prover.toml @@ -0,0 +1,2 @@ +x = "1" +y = "0" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/src/main.nr new file mode 100644 index 00000000000..4a74027e4aa --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/bool_or/src/main.nr @@ -0,0 +1,7 @@ +use dep::std; +fn main(x: u1, y: u1) { + assert(x | y == 1); + + assert(x | y | x == 1); +} + diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_oracle/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_oracle/src/main.nr index b8c3480f6ed..d3dad57456f 100644 --- a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_oracle/src/main.nr +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_oracle/src/main.nr @@ -8,14 +8,14 @@ fn main(x: Field) { } #[oracle(oracle_print_impl)] -unconstrained fn oracle_print(_x : Field) {} +unconstrained fn oracle_print(_x : Field) -> Field {} unconstrained fn oracle_print_wrapper(x: Field) { oracle_print(x); } #[oracle(oracle_print_array_impl)] -unconstrained fn oracle_print_array(_arr : [Field; 2]) {} +unconstrained fn oracle_print_array(_arr : [Field; 2]) -> Field {} unconstrained fn oracle_print_array_wrapper(arr: [Field; 2]) { oracle_print_array(arr); diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/Nargo.toml new file mode 100644 index 00000000000..d9434868157 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/Nargo.toml @@ -0,0 +1,7 @@ + + [package] + authors = [""] + compiler_version = "0.1" + + [dependencies] + \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/Prover.toml new file mode 100644 index 00000000000..f489cbac003 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/Prover.toml @@ -0,0 +1,2 @@ +x = "10" +y = "10" \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/src/main.nr new file mode 100644 index 00000000000..57af8120b33 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/cast_bool/src/main.nr @@ -0,0 +1,6 @@ +fn main(x: Field, y: Field) { + let z = x == y; + let t = z as u8; + assert(t == 1); +} + diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/Prover.toml new file mode 100644 index 00000000000..ec8d8e34856 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/Prover.toml @@ -0,0 +1 @@ +a = [1, 2, 3] diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/src/main.nr new file mode 100644 index 00000000000..04f08bb70c5 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_array_access/src/main.nr @@ -0,0 +1,17 @@ +fn main(a: [Field; 3]) { + let i = 1; + + // Using a comptime variable as a parameter should not make it non-comptime + let ii = foo(i); + let elem1 = a[i]; + + // Nor should using it in an expression with a non-comptime variable. + let two = i + ii; + assert(i == ii); + + let elem2 = a[i]; + assert(elem1 == elem2); + assert(two == 2); +} + +fn foo(x: Field) -> Field { x } diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/Prover.toml new file mode 100644 index 00000000000..745ce7c2361 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/Prover.toml @@ -0,0 +1,2 @@ +x = 5 +y = 6 diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/src/main.nr new file mode 100644 index 00000000000..0461fd9c4cb --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/comptime_recursion_regression/src/main.nr @@ -0,0 +1,4 @@ +fn main(x: Field, y: Field) { + let flag = (x == 1) | (y == 2); + assert(flag | false == flag); +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/contracts/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/contracts/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/contracts/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/contracts/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/contracts/Prover.toml new file mode 100644 index 00000000000..97d5b1e0eed --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/contracts/Prover.toml @@ -0,0 +1,2 @@ +x = 3 +y = 2 diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/contracts/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/contracts/src/main.nr new file mode 100644 index 00000000000..53e094eb4cc --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/contracts/src/main.nr @@ -0,0 +1,8 @@ +fn main(x : Field, y : pub Field) { + assert(x * 2 == y * 3); +} + +contract Foo { + fn double(x: Field) -> pub Field { x * 2 } + fn triple(x: Field) -> pub Field { x * 3 } +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/Prover.toml new file mode 100644 index 00000000000..f6597d3f78a --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/Prover.toml @@ -0,0 +1 @@ +input = "1" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/src/main.nr new file mode 100644 index 00000000000..ffc334179ee --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/hash_to_field/src/main.nr @@ -0,0 +1,5 @@ +use dep::std; + +fn main(input : Field) -> pub Field { + std::hash::hash_to_field([input]) +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/Nargo.toml new file mode 100644 index 00000000000..fb93b9aa2a7 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/Nargo.toml @@ -0,0 +1,6 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] + \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/Prover.toml new file mode 100644 index 00000000000..f932e0b4817 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/Prover.toml @@ -0,0 +1,2 @@ +x = true +y = [true, false] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/src/main.nr new file mode 100644 index 00000000000..0615a7dbca4 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/main_bool_arg/src/main.nr @@ -0,0 +1,8 @@ +fn main(x : bool, y: [bool;2]) { + if x { + assert(1 != 2); + } + + assert(x); + assert(y[0] != y[1]); +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/main_return/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/main_return/Nargo.toml new file mode 100644 index 00000000000..fb93b9aa2a7 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/main_return/Nargo.toml @@ -0,0 +1,6 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] + \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/main_return/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/main_return/Prover.toml new file mode 100644 index 00000000000..63e9878811a --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/main_return/Prover.toml @@ -0,0 +1 @@ +x = "8" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/main_return/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/main_return/src/main.nr new file mode 100644 index 00000000000..06347eb0919 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/main_return/src/main.nr @@ -0,0 +1,3 @@ +fn main(x: pub Field) -> pub Field { + x +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modules/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/modules/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modules/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modules/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/modules/Prover.toml new file mode 100644 index 00000000000..c0a0cdfbeb0 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modules/Prover.toml @@ -0,0 +1,2 @@ +x = "2" +y = "13" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modules/src/foo.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/modules/src/foo.nr new file mode 100644 index 00000000000..1f771fa9425 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modules/src/foo.nr @@ -0,0 +1,3 @@ +fn hello(x : Field) -> Field { + x +} \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modules/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/modules/src/main.nr new file mode 100644 index 00000000000..167f7e671a0 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modules/src/main.nr @@ -0,0 +1,14 @@ +mod foo; +// This is a comment. +// +// `main` is the entry point to a binary +// +// You can have a `Binary` or a `Library` +// Release : 0.2 +// +// To run a proof on the command line, type `cargo run prove {proof_name}` +// +// To verify that proof, type `cargo run verify {proof_name}` +fn main(x: Field, y: pub Field) { + assert(x != foo::hello(y)); +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/Prover.toml new file mode 100644 index 00000000000..39a4ddb9d15 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/Prover.toml @@ -0,0 +1,4 @@ + + x = "5" + y = "15" + \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/foo.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/foo.nr new file mode 100644 index 00000000000..ee0d20082f5 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/foo.nr @@ -0,0 +1,5 @@ +mod bar; + +fn hello(x : Field) -> Field { + x +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/foo/bar.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/foo/bar.nr new file mode 100644 index 00000000000..a92fb81dceb --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/foo/bar.nr @@ -0,0 +1,3 @@ +fn from_bar(x : Field) -> Field { + x +} \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/main.nr new file mode 100644 index 00000000000..8862e5a8650 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modules_more/src/main.nr @@ -0,0 +1,6 @@ +mod foo; + +// An example of the module system +fn main(x: Field, y: Field) { + assert(x != foo::bar::from_bar(y)); +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modulus/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/modulus/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modulus/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modulus/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/modulus/Prover.toml new file mode 100644 index 00000000000..d435609bb1a --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modulus/Prover.toml @@ -0,0 +1,290 @@ +bn254_modulus_be_bytes = [ + 48, + 100, + 78, + 114, + 225, + 49, + 160, + 41, + 184, + 80, + 69, + 182, + 129, + 129, + 88, + 93, + 40, + 51, + 232, + 72, + 121, + 185, + 112, + 145, + 67, + 225, + 245, + 147, + 240, + 0, + 0, + 1, +] +bn254_modulus_be_bits = [ + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, +] diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/modulus/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/modulus/src/main.nr new file mode 100644 index 00000000000..4a13a6e06ba --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/modulus/src/main.nr @@ -0,0 +1,27 @@ +use dep::std; + +fn main(bn254_modulus_be_bytes : [u8; 32], bn254_modulus_be_bits : [u1; 254]) -> pub Field { + let modulus_size = std::field::modulus_num_bits(); + // NOTE: The constraints used in this circuit will only work when testing nargo with the plonk bn254 backend + assert(modulus_size == 254); + + let modulus_be_byte_array = std::field::modulus_be_bytes(); + for i in 0..32 { + assert(modulus_be_byte_array[i] == bn254_modulus_be_bytes[i]); + } + let modulus_le_byte_array = std::field::modulus_le_bytes(); + for i in 0..32 { + assert(modulus_le_byte_array[i] == bn254_modulus_be_bytes[31-i]); + } + + let modulus_be_bits = std::field::modulus_be_bits(); + for i in 0..254 { + assert(modulus_be_bits[i] == bn254_modulus_be_bits[i]); + } + let modulus_le_bits = std::field::modulus_le_bits(); + for i in 0..254 { + assert(modulus_le_bits[i] == bn254_modulus_be_bits[253-i]); + } + + modulus_size +} \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/Nargo.toml new file mode 100644 index 00000000000..d9434868157 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/Nargo.toml @@ -0,0 +1,7 @@ + + [package] + authors = [""] + compiler_version = "0.1" + + [dependencies] + \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/Prover.toml new file mode 100644 index 00000000000..465ef562de4 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/Prover.toml @@ -0,0 +1,2 @@ +x = "1" +y = "1" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/src/main.nr new file mode 100644 index 00000000000..c7986cb7af3 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/pred_eq/src/main.nr @@ -0,0 +1,6 @@ +use dep::std; + +fn main(x: Field, y: Field) { + let p = x == y; + assert(p == true); +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/Nargo.toml new file mode 100644 index 00000000000..670888e37cd --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.6.0" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/Prover.toml new file mode 100644 index 00000000000..7d4290a117a --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/Prover.toml @@ -0,0 +1 @@ +x = 1 diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/src/main.nr new file mode 100644 index 00000000000..502aceac546 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/simple_mut/src/main.nr @@ -0,0 +1,7 @@ +// A simple program to test mutable variables + +fn main(x : Field) -> pub Field { + let mut y = 2; + y += x; + y +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/struct/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/struct/Nargo.toml new file mode 100644 index 00000000000..d9434868157 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/struct/Nargo.toml @@ -0,0 +1,7 @@ + + [package] + authors = [""] + compiler_version = "0.1" + + [dependencies] + \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/struct/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/struct/Prover.toml new file mode 100644 index 00000000000..7d59cc81807 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/struct/Prover.toml @@ -0,0 +1,2 @@ +x = "0" +y = "1" \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/struct/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/struct/src/main.nr new file mode 100644 index 00000000000..6d61393920d --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/struct/src/main.nr @@ -0,0 +1,77 @@ +use dep::std; + +struct Foo { + bar: Field, + array: [Field; 2], +} + +struct Pair { + first: Foo, + second: Field, +} + +impl Foo { + fn default(x: Field,y: Field) -> Self { + Self { bar: 0, array: [x,y] } + } +} + +impl Pair { + fn foo(p: Self) -> Foo { + p.first + } + + fn bar(self) -> Field { + self.foo().bar + } +} + +struct Nested { + a: Field, + b: Field +} +struct MyStruct { + my_bool: bool, + my_int: u32, + my_nest: Nested, +} +fn test_struct_in_tuple(a_bool : bool,x:Field, y:Field) -> (MyStruct, bool) { + let my_struct = MyStruct { + my_bool: a_bool, + my_int: 5, + my_nest: Nested{a:x,b:y}, + }; + (my_struct, a_bool) +} + +struct Animal { + legs: Field, + eyes: u8, +} + +fn get_dog() -> Animal { + let dog = Animal { legs: 4, eyes: 2 }; + dog +} + +fn main(x: Field, y: Field) { + let first = Foo::default(x,y); + let p = Pair { first, second: 1 }; + + assert(p.bar() == x); + assert(p.second == y); + assert(p.first.array[0] != p.first.array[1]); + + // Nested structs + let (struct_from_tuple, a_bool) = test_struct_in_tuple(true,x,y); + assert(struct_from_tuple.my_bool == true); + assert(a_bool == true); + assert(struct_from_tuple.my_int == 5); + assert(struct_from_tuple.my_nest.a == 0); + + // Regression test for issue #670 + let Animal { legs, eyes } = get_dog(); + let six = legs + eyes as Field; + + assert(six == 6); +} diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/Prover.toml new file mode 100644 index 00000000000..70640bba4cc --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/Prover.toml @@ -0,0 +1,3 @@ +[y] +foo = "5" +bar = "7" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/src/main.nr new file mode 100644 index 00000000000..0d6e411addf --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/struct_fields_ordering/src/main.nr @@ -0,0 +1,14 @@ +use dep::std; + +// Note that fields are not in alphabetical order. +// We want to check that this ordering is maintained +struct myStruct { + foo: u32, + bar: Field, +} + +fn main(y : pub myStruct) { + assert(y.foo == 5); + assert(y.bar == 7); +} + diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/submodules/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/submodules/Nargo.toml new file mode 100644 index 00000000000..d9434868157 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/submodules/Nargo.toml @@ -0,0 +1,7 @@ + + [package] + authors = [""] + compiler_version = "0.1" + + [dependencies] + \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/submodules/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/submodules/Prover.toml new file mode 100644 index 00000000000..b6626a67e19 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/submodules/Prover.toml @@ -0,0 +1,2 @@ +x = 1 +y = 0 diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/submodules/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/submodules/src/main.nr new file mode 100644 index 00000000000..9bfe382663f --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/submodules/src/main.nr @@ -0,0 +1,17 @@ +use mysubmodule::my_helper; + +fn main(x: u1, y: u1) { + my_helper(); + mysubmodule::my_bool_or(x, y); +} + +mod mysubmodule { + use dep::std; + + fn my_bool_or(x: u1, y: u1) { + assert(x | y == 1); + } + + fn my_helper() {} +} + diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/xor/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/xor/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/xor/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/xor/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/xor/Prover.toml new file mode 100644 index 00000000000..f28f2f8cc48 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/xor/Prover.toml @@ -0,0 +1,2 @@ +x = "5" +y = "10" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/xor/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/xor/src/main.nr new file mode 100644 index 00000000000..e893c938fc3 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/xor/src/main.nr @@ -0,0 +1,5 @@ +fn main(x : u32, y : pub u32) { + let m = x ^ y; + + assert(m != 10); +} \ No newline at end of file diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen.rs b/crates/noirc_evaluator/src/brillig/brillig_gen.rs index ac2cd6a09c8..ffb826acc3d 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen.rs @@ -270,7 +270,6 @@ impl BrilligGen { match typ { Type::Numeric(_) => RegisterValueOrArray::RegisterIndex(register_index), Type::Array(_, size) => RegisterValueOrArray::HeapArray(register_index, size), - Type::Unit => RegisterValueOrArray::RegisterIndex(register_index), _ => { unreachable!("type not supported for conversion into brillig register") } diff --git a/crates/noirc_evaluator/src/ssa_refactor.rs b/crates/noirc_evaluator/src/ssa_refactor.rs index 827a221b15b..476cfae1716 100644 --- a/crates/noirc_evaluator/src/ssa_refactor.rs +++ b/crates/noirc_evaluator/src/ssa_refactor.rs @@ -43,6 +43,8 @@ pub(crate) fn optimize_into_acir(program: Program, allow_log_ops: bool) -> Gener .print("After Mem2Reg:") .fold_constants() .print("After Constant Folding:") + .dead_instruction_elimination() + .print("After Dead Instruction Elimination:") .into_acir(brillig, allow_log_ops) } diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs index 507eeb0fd4d..4cd89006afc 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs @@ -524,6 +524,7 @@ impl AcirContext { lhs: AcirVar, rhs: AcirVar, bit_size: u32, + predicate: Option, ) -> Result { let lhs_data = &self.vars[lhs]; let rhs_data = &self.vars[rhs]; @@ -533,8 +534,13 @@ impl AcirContext { // TODO: check what happens when we do (a as u8) >= (b as u32) // TODO: The frontend should shout in this case + + let predicate = predicate.map(|acir_var| { + let predicate_data = &self.vars[acir_var]; + predicate_data.to_expression().into_owned() + }); let is_greater_than_eq = - self.acir_ir.more_than_eq_comparison(&lhs_expr, &rhs_expr, bit_size)?; + self.acir_ir.more_than_eq_comparison(&lhs_expr, &rhs_expr, bit_size, predicate)?; Ok(self.add_data(AcirVarData::Witness(is_greater_than_eq))) } @@ -546,10 +552,11 @@ impl AcirContext { lhs: AcirVar, rhs: AcirVar, bit_size: u32, + predicate: Option, ) -> Result { // Flip the result of calling more than equal method to // compute less than. - let comparison = self.more_than_eq_var(lhs, rhs, bit_size)?; + let comparison = self.more_than_eq_var(lhs, rhs, bit_size, predicate)?; let one = self.add_constant(FieldElement::one()); self.sub_var(one, comparison) // comparison_negated diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index 084cd050578..04b4ff1c0b9 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -622,6 +622,7 @@ impl GeneratedAcir { a: &Expression, b: &Expression, max_bits: u32, + predicate: Option, ) -> Result { // Ensure that 2^{max_bits + 1} is less than the field size // @@ -667,7 +668,7 @@ impl GeneratedAcir { b: Expression::from_field(two_max_bits), q: q_witness, r: r_witness, - predicate: None, + predicate, }))); // Add constraint to ensure `r` is correctly bounded diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs index 384f02630d2..3dcaf3de7b2 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/mod.rs @@ -40,6 +40,10 @@ struct Context { /// already exists for this Value, we return the `AcirVar`. ssa_values: HashMap, AcirValue>, + /// The `AcirVar` that describes the condition belonging to the most recently invoked + /// `SideEffectsEnabled` instruction. + current_side_effects_enabled_var: Option, + /// Manages and builds the `AcirVar`s to which the converted SSA values refer. acir_context: AcirContext, } @@ -177,13 +181,7 @@ impl Context { // Generate the brillig code of the function let code = BrilligArtifact::default().link(&brillig[*id]); - let mut outputs: Vec = Vec::new(); - if Self::is_return_type_unit(result_ids, dfg) { - self.acir_context.brillig(code, inputs, vec![]); - return; - } else { - outputs.extend(vecmap(result_ids, |result_id| dfg.type_of_value(*result_id).into())); - } + let outputs: Vec = vecmap(result_ids, |result_id| dfg.type_of_value(*result_id).into()); let output_values = self.acir_context.brillig(code, inputs, outputs); // Compiler sanity check @@ -229,6 +227,10 @@ impl Context { .expect("add Result types to all methods so errors bubble up"); self.define_result_var(dfg, instruction_id, result_acir_var); } + Instruction::EnableSideEffects { condition } => { + let acir_var = self.convert_numeric_value(*condition, dfg); + self.current_side_effects_enabled_var = Some(acir_var); + } Instruction::ArrayGet { array, index } => { self.handle_array_operation(instruction_id, *array, *index, None, dfg); } @@ -306,10 +308,6 @@ impl Context { _ => unreachable!("ICE: Program must have a singular return"), }; - if Self::is_return_type_unit(return_values, dfg) { - return; - } - // The return value may or may not be an array reference. Calling `flatten_value_list` // will expand the array if there is one. let return_acir_vars = self.flatten_value_list(return_values, dfg); @@ -332,6 +330,7 @@ impl Context { /// involving such values are evaluated via a separate path and stored in /// `ssa_value_to_array_address` instead. fn convert_value(&mut self, value_id: ValueId, dfg: &DataFlowGraph) -> AcirValue { + let value_id = dfg.resolve(value_id); let value = &dfg[value_id]; if let Some(acir_value) = self.ssa_values.get(&value_id) { return acir_value.clone(); @@ -414,7 +413,12 @@ impl Context { // Note: that this produces unnecessary constraints when // this Eq instruction is being used for a constrain statement BinaryOp::Eq => self.acir_context.eq_var(lhs, rhs), - BinaryOp::Lt => self.acir_context.less_than_var(lhs, rhs, bit_count), + BinaryOp::Lt => self.acir_context.less_than_var( + lhs, + rhs, + bit_count, + self.current_side_effects_enabled_var, + ), BinaryOp::Shl => self.acir_context.shift_left_var(lhs, rhs, binary_type), BinaryOp::Shr => self.acir_context.shift_right_var(lhs, rhs, binary_type), BinaryOp::Xor => self.acir_context.xor_var(lhs, rhs, binary_type), @@ -453,9 +457,6 @@ impl Context { (_, Type::Array(..)) | (Type::Array(..), _) => { unreachable!("Arrays are invalid in binary operations") } - // Unit type currently can mean a 0 constant, so we return the - // other type. - (typ, Type::Unit) | (Type::Unit, typ) => typ, // If either side is a Field constant then, we coerce into the type // of the other operand (Type::Numeric(NumericType::NativeField), typ) @@ -637,12 +638,6 @@ impl Context { } } } - - /// Check if the program returns the `Unit/None` type. - /// This type signifies that the program returns nothing. - fn is_return_type_unit(return_values: &[ValueId], dfg: &DataFlowGraph) -> bool { - return_values.len() == 1 && dfg.type_of_value(return_values[0]) == Type::Unit - } } #[cfg(test)] diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs index 58673d81552..13b5bb01b2c 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/dfg.rs @@ -64,6 +64,11 @@ pub(crate) struct DataFlowGraph { /// All blocks in a function blocks: DenseMap, + + /// Debugging information about which `ValueId`s have had their underlying `Value` substituted + /// for that of another. This information is purely used for printing the SSA, and has no + /// material effect on the SSA itself. + replaced_value_ids: HashMap, } impl DataFlowGraph { @@ -151,19 +156,28 @@ impl DataFlowGraph { self.values.insert(value) } - /// Replaces the value specified by the given ValueId with a new Value. + /// Set the value of value_to_replace to refer to the value referred to by new_value. /// /// This is the preferred method to call for optimizations simplifying /// values since other instructions referring to the same ValueId need /// not be modified to refer to a new ValueId. - pub(crate) fn set_value(&mut self, value_id: ValueId, new_value: Value) { - self.values[value_id] = new_value; + pub(crate) fn set_value_from_id(&mut self, value_to_replace: ValueId, new_value: ValueId) { + if value_to_replace != new_value { + self.replaced_value_ids.insert(value_to_replace, self.resolve(new_value)); + let new_value = self.values[new_value].clone(); + self.values[value_to_replace] = new_value; + } } - /// Set the value of value_to_replace to refer to the value referred to by new_value. - pub(crate) fn set_value_from_id(&mut self, value_to_replace: ValueId, new_value: ValueId) { - let new_value = self.values[new_value].clone(); - self.values[value_to_replace] = new_value; + /// If `original_value_id`'s underlying `Value` has been substituted for that of another + /// `ValueId`, this function will return the `ValueId` from which the substitution was taken. + /// If `original_value_id`'s underlying `Value` has not been substituted, the same `ValueId` + /// is returned. + pub(crate) fn resolve(&self, original_value_id: ValueId) -> ValueId { + match self.replaced_value_ids.get(&original_value_id) { + Some(id) => self.resolve(*id), + None => original_value_id, + } } /// Creates a new constant value, or returns the Id to an existing one if diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs index abdd910ef9f..bb16f144f55 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs @@ -103,6 +103,15 @@ pub(crate) enum Instruction { /// Writes a value to memory. Store { address: ValueId, value: ValueId }, + /// Provides a context for all instructions that follow up until the next + /// `EnableSideEffects` is encountered, for stating a condition that determines whether + /// such instructions are allowed to have side-effects. + /// + /// This instruction is only emitted after the cfg flattening pass, and is used to annotate + /// instruction regions with an condition that corresponds to their position in the CFG's + /// if-branching structure. + EnableSideEffects { condition: ValueId }, + /// Retrieve a value from an array at the given index ArrayGet { array: ValueId, index: ValueId }, @@ -127,7 +136,9 @@ impl Instruction { InstructionResultType::Operand(*value) } Instruction::ArraySet { array, .. } => InstructionResultType::Operand(*array), - Instruction::Constrain(_) | Instruction::Store { .. } => InstructionResultType::None, + Instruction::Constrain(_) + | Instruction::Store { .. } + | Instruction::EnableSideEffects { .. } => InstructionResultType::None, Instruction::Load { .. } | Instruction::ArrayGet { .. } | Instruction::Call { .. } => { InstructionResultType::Unknown } @@ -167,6 +178,9 @@ impl Instruction { Instruction::Store { address, value } => { Instruction::Store { address: f(*address), value: f(*value) } } + Instruction::EnableSideEffects { condition } => { + Instruction::EnableSideEffects { condition: f(*condition) } + } Instruction::ArrayGet { array, index } => { Instruction::ArrayGet { array: f(*array), index: f(*index) } } @@ -176,6 +190,46 @@ impl Instruction { } } + /// Applies a function to each input value this instruction holds. + pub(crate) fn for_each_value(&self, mut f: impl FnMut(ValueId) -> T) { + match self { + Instruction::Binary(binary) => { + f(binary.lhs); + f(binary.rhs); + } + Instruction::Call { func, arguments } => { + f(*func); + for argument in arguments { + f(*argument); + } + } + Instruction::Cast(value, _) + | Instruction::Not(value) + | Instruction::Truncate { value, .. } + | Instruction::Constrain(value) + | Instruction::Load { address: value } => { + f(*value); + } + Instruction::Store { address, value } => { + f(*address); + f(*value); + } + Instruction::Allocate { .. } => (), + Instruction::ArrayGet { array, index } => { + f(*array); + f(*index); + } + Instruction::ArraySet { array, index, value } => { + f(*array); + f(*index); + f(*value); + } + Instruction::EnableSideEffects { condition } => { + f(*condition); + } + } + } + /// Try to simplify this instruction. If the instruction can be simplified to a known value, /// that value is returned. Otherwise None is returned. pub(crate) fn simplify(&self, dfg: &mut DataFlowGraph) -> SimplifyResult { @@ -252,10 +306,11 @@ impl Instruction { None } } - Instruction::Call { .. } - | Instruction::Allocate { .. } - | Instruction::Load { .. } - | Instruction::Store { .. } => None, + Instruction::Call { .. } => None, + Instruction::Allocate { .. } => None, + Instruction::Load { .. } => None, + Instruction::Store { .. } => None, + Instruction::EnableSideEffects { .. } => None, } } } @@ -329,6 +384,26 @@ impl TerminatorInstruction { } } + /// Apply a function to each value + pub(crate) fn for_each_value(&self, mut f: impl FnMut(ValueId) -> T) { + use TerminatorInstruction::*; + match self { + JmpIf { condition, .. } => { + f(*condition); + } + Jmp { arguments, .. } => { + for argument in arguments { + f(*argument); + } + } + Return { return_values } => { + for return_value in return_values { + f(*return_value); + } + } + } + } + /// Mutate each BlockId to a new BlockId specified by the given mapping function. pub(crate) fn mutate_blocks(&mut self, mut f: impl FnMut(BasicBlockId) -> BasicBlockId) { use TerminatorInstruction::*; diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/printer.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/printer.rs index 79332fc5cdc..071f1a16029 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/printer.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/printer.rs @@ -61,6 +61,7 @@ pub(crate) fn display_block( /// constant or a function we print those directly. fn value(function: &Function, id: ValueId) -> String { use super::value::Value; + let id = function.dfg.resolve(id); match &function.dfg[id] { Value::NumericConstant { constant, typ } => { format!("{typ} {constant}") @@ -155,6 +156,9 @@ pub(crate) fn display_instruction( Instruction::Store { address, value } => { writeln!(f, "store {} at {}", show(*value), show(*address)) } + Instruction::EnableSideEffects { condition } => { + writeln!(f, "enable_side_effects {}", show(*condition)) + } Instruction::ArrayGet { array, index } => { writeln!(f, "array_get {}, index {}", show(*array), show(*index)) } diff --git a/crates/noirc_evaluator/src/ssa_refactor/ir/types.rs b/crates/noirc_evaluator/src/ssa_refactor/ir/types.rs index d4a3946375a..a9285531203 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ir/types.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ir/types.rs @@ -31,9 +31,6 @@ pub(crate) enum Type { /// A function that may be called directly Function, - - /// The Unit type with a single value - Unit, } impl Type { @@ -78,7 +75,6 @@ impl std::fmt::Display for Type { write!(f, "[{}; {length}]", elements.join(", ")) } Type::Function => write!(f, "function"), - Type::Unit => write!(f, "unit"), } } } diff --git a/crates/noirc_evaluator/src/ssa_refactor/opt/constant_folding.rs b/crates/noirc_evaluator/src/ssa_refactor/opt/constant_folding.rs index 5a36ab799c7..8b0db177500 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/opt/constant_folding.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/opt/constant_folding.rs @@ -56,9 +56,9 @@ impl Context { for instruction in instructions { self.push_instruction(function, block, instruction); } - - let terminator = - function.dfg[block].unwrap_terminator().map_values(|value| self.get_value(value)); + let terminator = function.dfg[block] + .unwrap_terminator() + .map_values(|value| self.get_value(function.dfg.resolve(value))); function.dfg.set_block_terminator(block, terminator); self.block_queue.extend(function.dfg[block].successors()); @@ -74,8 +74,9 @@ impl Context { block: BasicBlockId, id: InstructionId, ) { - let instruction = function.dfg[id].map_values(|id| self.get_value(id)); - let results = function.dfg.instruction_results(id).to_vec(); + let instruction = + function.dfg[id].map_values(|id| self.get_value(function.dfg.resolve(id))); + let results = vecmap(function.dfg.instruction_results(id), |id| function.dfg.resolve(*id)); let ctrl_typevars = instruction .requires_ctrl_typevars() diff --git a/crates/noirc_evaluator/src/ssa_refactor/opt/die.rs b/crates/noirc_evaluator/src/ssa_refactor/opt/die.rs new file mode 100644 index 00000000000..1eda042abfa --- /dev/null +++ b/crates/noirc_evaluator/src/ssa_refactor/opt/die.rs @@ -0,0 +1,194 @@ +//! Dead Instruction Elimination (DIE) pass: Removes any instruction without side-effects for +//! which the results are unused. +use std::collections::HashSet; + +use crate::ssa_refactor::{ + ir::{ + basic_block::{BasicBlock, BasicBlockId}, + function::Function, + instruction::{Instruction, InstructionId}, + post_order::PostOrder, + value::ValueId, + }, + ssa_gen::Ssa, +}; + +impl Ssa { + /// Performs Dead Instruction Elimination (DIE) to remove any instructions with + /// unused results. + pub(crate) fn dead_instruction_elimination(mut self) -> Ssa { + for function in self.functions.values_mut() { + dead_instruction_elimination(function); + } + self + } +} + +/// Removes any unused instructions in the reachable blocks of the given function. +/// +/// The blocks of the function are iterated in post order, such that any blocks containing +/// instructions that reference results from an instruction in another block are evaluated first. +/// If we did not iterate blocks in this order we could not safely say whether or not the results +/// of its instructions are needed elsewhere. +fn dead_instruction_elimination(function: &mut Function) { + let mut context = Context::default(); + let blocks = PostOrder::with_function(function); + + for block in blocks.as_slice() { + context.remove_unused_instructions_in_block(function, *block); + } +} + +/// Per function context for tracking unused values and which instructions to remove. +#[derive(Default)] +struct Context { + used_values: HashSet, + instructions_to_remove: HashSet, +} + +impl Context { + /// Steps backwards through the instruction of the given block, amassing a set of used values + /// as it goes, and at the same time marking instructions for removal if they haven't appeared + /// in the set thus far. + /// + /// It is not only safe to mark instructions for removal as we go because no instruction + /// result value can be referenced before the occurrence of the instruction that produced it, + /// and we are iterating backwards. It is also important to identify instructions that can be + /// removed as we go, such that we know not to include its referenced values in the used + /// values set. This allows DIE to identify whole chains of unused instructions. (If the + /// values referenced by an unused instruction were considered to be used, only the head of + /// such chains would be removed.) + fn remove_unused_instructions_in_block( + &mut self, + function: &mut Function, + block_id: BasicBlockId, + ) { + let block = &function.dfg[block_id]; + self.mark_terminator_values_as_used(block); + + for instruction in block.instructions().iter().rev() { + if self.is_unused(*instruction, function) { + self.instructions_to_remove.insert(*instruction); + } else { + let instruction = &function.dfg[*instruction]; + instruction.for_each_value(|value| self.used_values.insert(value)); + } + } + + function.dfg[block_id] + .instructions_mut() + .retain(|instruction| !self.instructions_to_remove.contains(instruction)); + } + + /// Returns true if an instruction can be removed. + /// + /// An instruction can be removed as long as it has no side-effects, and none of its result + /// values have been referenced. + fn is_unused(&self, instruction_id: InstructionId, function: &Function) -> bool { + use Instruction::*; + + let instruction = &function.dfg[instruction_id]; + + // These instruction types cannot be removed + if matches!(instruction, Constrain(_) | Call { .. } | Store { .. }) { + return false; + } + + let results = function.dfg.instruction_results(instruction_id); + results.iter().all(|result| !self.used_values.contains(result)) + } + + /// Adds values referenced by the terminator to the set of used values. + fn mark_terminator_values_as_used(&mut self, block: &BasicBlock) { + block.unwrap_terminator().for_each_value(|value| self.used_values.insert(value)); + } +} + +#[cfg(test)] +mod test { + use crate::ssa_refactor::{ + ir::{function::RuntimeType, instruction::BinaryOp, map::Id, types::Type}, + ssa_builder::FunctionBuilder, + }; + + #[test] + fn dead_instruction_elimination() { + // fn main f0 { + // b0(v0: Field): + // v1 = add v0, Field 1 + // v2 = add v0, Field 2 + // jmp b1(v2) + // b1(v3: Field): + // v4 = allocate 1 field + // v5 = load v4 + // v6 = allocate 1 field + // store Field 1 in v6 + // v7 = load v6 + // v8 = add v7, Field 1 + // v9 = add v7, Field 2 + // v10 = add v7, Field 3 + // v11 = add v10, v10 + // call println(v8) + // return v9 + // } + let main_id = Id::test_new(0); + let println_id = Id::test_new(1); + + // Compiling main + let mut builder = FunctionBuilder::new("main".into(), main_id, RuntimeType::Acir); + let v0 = builder.add_parameter(Type::field()); + let b1 = builder.insert_block(); + + let one = builder.field_constant(1u128); + let two = builder.field_constant(2u128); + let three = builder.field_constant(3u128); + + let _v1 = builder.insert_binary(v0, BinaryOp::Add, one); + let v2 = builder.insert_binary(v0, BinaryOp::Add, two); + builder.terminate_with_jmp(b1, vec![v2]); + + builder.switch_to_block(b1); + let _v3 = builder.add_block_parameter(b1, Type::field()); + + let v4 = builder.insert_allocate(); + let _v5 = builder.insert_load(v4, Type::field()); + + let v6 = builder.insert_allocate(); + builder.insert_store(v6, one); + let v7 = builder.insert_load(v6, Type::field()); + let v8 = builder.insert_binary(v7, BinaryOp::Add, one); + let v9 = builder.insert_binary(v7, BinaryOp::Add, two); + let v10 = builder.insert_binary(v7, BinaryOp::Add, three); + let _v11 = builder.insert_binary(v10, BinaryOp::Add, v10); + builder.insert_call(println_id, vec![v8], vec![]); + builder.terminate_with_return(vec![v9]); + + let ssa = builder.finish(); + let main = ssa.main(); + + // The instruction count never includes the terminator instruction + assert_eq!(main.dfg[main.entry_block()].instructions().len(), 2); + assert_eq!(main.dfg[b1].instructions().len(), 10); + + // Expected output: + // + // fn main f0 { + // b0(v0: Field): + // v2 = add v0, Field 2 + // jmp b1(v2) + // b1(v3: Field): + // v6 = allocate 1 field + // store Field 1 in v6 + // v7 = load v6 + // v8 = add v7, Field 1 + // v9 = add v7, Field 2 + // call println(v8) + // return v9 + // } + let ssa = ssa.dead_instruction_elimination(); + let main = ssa.main(); + + assert_eq!(main.dfg[main.entry_block()].instructions().len(), 1); + assert_eq!(main.dfg[b1].instructions().len(), 6); + } +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/opt/flatten_cfg.rs b/crates/noirc_evaluator/src/ssa_refactor/opt/flatten_cfg.rs index 313400e8438..113a51629d3 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/opt/flatten_cfg.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/opt/flatten_cfg.rs @@ -10,6 +10,26 @@ //! while merging branches. These extra instructions can be cleaned up by a later dead instruction //! elimination (DIE) pass. //! +//! Though CFG information is lost during this pass, some key information is retained in the form +//! of `EnableSideEffect` instructions. Each time the flattening pass enters and exits a branch of +//! a jmpif, an instruction is inserted to capture a condition that is analogous to the activeness +//! of the program point. For example: +//! +//! b0(v0: u1): +//! jmpif v0, then: b1, else: b2 +//! b1(): +//! v1 = call f0 +//! jmp b3(v1) +//! ... blocks b2 & b3 ... +//! +//! Would brace the call instruction as such: +//! enable_side_effects v0 +//! v1 = call f0 +//! enable_side_effects u1 1 +//! +//! (Note: we restore to "true" to indicate that this program point is not nested within any +//! other branches.) +//! //! When we are flattening a block that was reached via a jmpif with a non-constant condition c, //! the following transformations of certain instructions within the block are expected: //! @@ -297,6 +317,8 @@ impl<'f> Context<'f> { let else_branch = self.inline_branch(block, else_block, old_condition, else_condition, zero); + self.insert_current_side_effects_enabled(); + // While there is a condition on the stack we don't compile outside the condition // until it is popped. This ensures we inline the full then and else branches // before continuing from the end of the conditional here where they can be merged properly. @@ -368,6 +390,20 @@ impl<'f> Context<'f> { self.function.dfg.insert_instruction_and_results(instruction, block, ctrl_typevars) } + /// Checks the branch condition on the top of the stack and uses it to build and insert an + /// `EnableSideEffects` instruction into the entry block. + /// + /// If the stack is empty, a "true" u1 constant is taken to be the active condition. This is + /// necessary for re-enabling side-effects when re-emerging to a branch depth of 0. + fn insert_current_side_effects_enabled(&mut self) { + let condition = match self.conditions.last() { + Some((_, cond)) => *cond, + None => self.function.dfg.make_constant(FieldElement::one(), Type::unsigned(1)), + }; + let enable_side_effects = Instruction::EnableSideEffects { condition }; + self.insert_instruction_with_typevars(enable_side_effects, None); + } + /// Merge two values a and b from separate basic blocks to a single value. This /// function would return the result of `if c { a } else { b }` as `c*a + (!c)*b`. fn merge_values( @@ -406,6 +442,7 @@ impl<'f> Context<'f> { condition_value: FieldElement, ) -> Branch { self.push_condition(jmpif_block, new_condition); + self.insert_current_side_effects_enabled(); let old_stores = std::mem::take(&mut self.store_values); // Remember the old condition value is now known to be true/false within this branch @@ -534,7 +571,8 @@ impl<'f> Context<'f> { fn push_instruction(&mut self, id: InstructionId) { let instruction = self.function.dfg[id].map_values(|id| self.translate_value(id)); let instruction = self.handle_instruction_side_effects(instruction); - let results = self.function.dfg.instruction_results(id).to_vec(); + let results = self.function.dfg.instruction_results(id); + let results = vecmap(results, |id| self.function.dfg.resolve(*id)); let ctrl_typevars = instruction .requires_ctrl_typevars() @@ -652,11 +690,13 @@ mod test { // Expected output: // fn main f0 { // b0(v0: u1): - // v4 = not v0 - // v5 = mul v0, Field 3 - // v7 = not v0 - // v8 = mul v7, Field 4 - // v9 = add v5, v8 + // enable_side_effects v0 + // v5 = not v0 + // enable_side_effects v5 + // enable_side_effects u1 1 + // v7 = mul v0, Field 3 + // v8 = mul v5, Field 4 + // v9 = add v7, v8 // return v9 // } let ssa = ssa.flatten_cfg(); @@ -695,13 +735,17 @@ mod test { let ssa = builder.finish(); assert_eq!(ssa.main().reachable_blocks().len(), 3); - // Expected output (sans useless extra 'not' instruction): + // Expected output: // fn main f0 { // b0(v0: u1, v1: u1): - // v2 = mul v1, v0 - // v3 = eq v2, v0 - // constrain v3 - // return v1 + // enable_side_effects v0 + // v3 = mul v1, v0 + // v4 = eq v3, v0 + // constrain v4 + // v5 = not v0 + // enable_side_effects v5 + // enable_side_effects u1 1 + // return // } let ssa = ssa.flatten_cfg(); assert_eq!(ssa.main().reachable_blocks().len(), 1); @@ -742,14 +786,16 @@ mod test { // Expected output: // fn main f0 { // b0(v0: u1, v1: reference): + // enable_side_effects v0 // v4 = load v1 // store Field 5 at v1 // v5 = not v0 + // enable_side_effects v5 + // enable_side_effects u1 1 // v7 = mul v0, Field 5 - // v8 = not v0 - // v9 = mul v8, v4 - // v10 = add v7, v9 - // store v10 at v1 + // v8 = mul v5, v4 + // v9 = add v7, v8 + // store v9 at v1 // return // } let ssa = ssa.flatten_cfg(); @@ -816,21 +862,24 @@ mod test { // Expected output: // fn main f0 { // b0(v0: u1, v1: reference): - // v8 = add v1, Field 1 - // v9 = load v8 - // store Field 5 at v8 - // v10 = not v0 - // v12 = add v1, Field 1 - // v13 = load v12 - // store Field 6 at v12 - // v14 = mul v0, Field 5 - // v15 = mul v10, v9 - // v16 = add v14, v15 - // store v16 at v8 - // v17 = mul v0, v13 - // v18 = mul v10, Field 6 - // v19 = add v17, v18 - // store v19 at v12 + // enable_side_effects v0 + // v7 = add v1, Field 1 + // v8 = load v7 + // store Field 5 at v7 + // v9 = not v0 + // enable_side_effects v9 + // v11 = add v1, Field 1 + // v12 = load v11 + // store Field 6 at v11 + // enable_side_effects Field 1 + // v13 = mul v0, Field 5 + // v14 = mul v9, v8 + // v15 = add v13, v14 + // store v15 at v7 + // v16 = mul v0, v12 + // v17 = mul v9, Field 6 + // v18 = add v16, v17 + // store v18 at v11 // return // } let ssa = ssa.flatten_cfg(); @@ -1022,31 +1071,38 @@ mod test { // b0(v0: u1, v1: u1): // call println(Field 0, Field 0) // call println(Field 1, Field 1) + // enable_side_effects v0 // call println(Field 2, Field 2) - // call println(Field 4, Field 2) ; block 4 does not store a value - // v45 = and v0, v1 + // call println(Field 4, Field 2) + // v29 = and v0, v1 + // enable_side_effects v29 // call println(Field 5, Field 5) - // v49 = not v1 - // v50 = and v0, v49 + // v32 = not v1 + // v33 = and v0, v32 + // enable_side_effects v33 // call println(Field 6, Field 6) - // v54 = mul v1, Field 5 - // v55 = mul v49, Field 2 - // v56 = add v54, v55 - // v57 = mul v1, Field 5 - // v58 = mul v49, Field 6 - // v59 = add v57, v58 - // call println(Field 7, v59) ; v59 = 5 and 6 merged - // v61 = not v0 + // enable_side_effects v0 + // v36 = mul v1, Field 5 + // v37 = mul v32, Field 2 + // v38 = add v36, v37 + // v39 = mul v1, Field 5 + // v40 = mul v32, Field 6 + // v41 = add v39, v40 + // call println(Field 7, v42) + // v43 = not v0 + // enable_side_effects v43 + // store Field 3 at v2 // call println(Field 3, Field 3) - // call println(Field 8, Field 3) ; block 8 does not store a value - // v66 = mul v0, v59 - // v67 = mul v61, Field 1 - // v68 = add v66, v67 ; This was from an unused store. - // v69 = mul v0, v59 - // v70 = mul v61, Field 3 - // v71 = add v69, v70 - // call println(Field 9, v71) ; v71 = 3, 5, and 6 merged - // return v71 + // call println(Field 8, Field 3) + // enable_side_effects Field 1 + // v47 = mul v0, v41 + // v48 = mul v43, Field 1 + // v49 = add v47, v48 + // v50 = mul v0, v44 + // v51 = mul v43, Field 3 + // v52 = add v50, v51 + // call println(Field 9, v53) + // return v54 // } let main = ssa.main(); diff --git a/crates/noirc_evaluator/src/ssa_refactor/opt/inlining.rs b/crates/noirc_evaluator/src/ssa_refactor/opt/inlining.rs index aad3462e50b..c8a36faceb3 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/opt/inlining.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/opt/inlining.rs @@ -365,13 +365,14 @@ impl<'function> PerFunctionContext<'function> { fn push_instruction(&mut self, id: InstructionId) { let instruction = self.source_function.dfg[id].map_values(|id| self.translate_value(id)); let results = self.source_function.dfg.instruction_results(id); + let results = vecmap(results, |id| self.source_function.dfg.resolve(*id)); let ctrl_typevars = instruction .requires_ctrl_typevars() - .then(|| vecmap(results, |result| self.source_function.dfg.type_of_value(*result))); + .then(|| vecmap(&results, |result| self.source_function.dfg.type_of_value(*result))); let new_results = self.context.builder.insert_instruction(instruction, ctrl_typevars); - Self::insert_new_instruction_results(&mut self.values, results, new_results); + Self::insert_new_instruction_results(&mut self.values, &results, new_results); } /// Modify the values HashMap to remember the mapping between an instruction result's previous diff --git a/crates/noirc_evaluator/src/ssa_refactor/opt/mem2reg.rs b/crates/noirc_evaluator/src/ssa_refactor/opt/mem2reg.rs index 4166512f695..580ec8a495a 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/opt/mem2reg.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/opt/mem2reg.rs @@ -103,8 +103,7 @@ impl PerBlockContext { Instruction::Load { address } => { if let Some(address) = self.try_const_address(*address, dfg) { if let Some(last_value) = self.last_stores.get(&address) { - let last_value = dfg[*last_value].clone(); - loads_to_substitute.push((*instruction_id, last_value)); + loads_to_substitute.push((*instruction_id, *last_value)); } else { self.failed_substitutes.insert(address); } @@ -138,7 +137,7 @@ impl PerBlockContext { .instruction_results(*instruction_id) .first() .expect("ICE: Load instructions should have single result"); - dfg.set_value(result_value, new_value.clone()); + dfg.set_value_from_id(result_value, *new_value); } // Delete load instructions @@ -293,7 +292,7 @@ mod tests { // v0 = allocate // store v0, Field 1 // v1 = load v0 - // v2 = call f0(v0) + // call f0(v0) // return v1 // } @@ -304,7 +303,7 @@ mod tests { builder.insert_store(v0, one); let v1 = builder.insert_load(v0, Type::field()); let f0 = builder.import_intrinsic_id(Intrinsic::Println); - builder.insert_call(f0, vec![v0], vec![Type::Unit]); + builder.insert_call(f0, vec![v0], vec![]); builder.terminate_with_return(vec![v1]); let ssa = builder.finish().mem2reg(); diff --git a/crates/noirc_evaluator/src/ssa_refactor/opt/mod.rs b/crates/noirc_evaluator/src/ssa_refactor/opt/mod.rs index fcb30f09ae5..56c5fa689ad 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/opt/mod.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/opt/mod.rs @@ -4,6 +4,7 @@ //! simpler form until the IR only has a single function remaining with 1 block within it. //! Generally, these passes are also expected to minimize the final amount of instructions. mod constant_folding; +mod die; mod flatten_cfg; mod inlining; mod mem2reg; diff --git a/crates/noirc_evaluator/src/ssa_refactor/opt/unrolling.rs b/crates/noirc_evaluator/src/ssa_refactor/opt/unrolling.rs index 72026ed81ae..b420b4ca4f0 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/opt/unrolling.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/opt/unrolling.rs @@ -441,7 +441,8 @@ impl<'f> LoopIteration<'f> { fn push_instruction(&mut self, id: InstructionId) { let instruction = self.function.dfg[id].map_values(|id| self.get_value(id)); - let results = self.function.dfg.instruction_results(id).to_vec(); + let results = self.function.dfg.instruction_results(id); + let results = vecmap(results, |id| self.function.dfg.resolve(*id)); let ctrl_typevars = instruction .requires_ctrl_typevars() diff --git a/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/context.rs b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/context.rs index 3f8b6f3885a..49a5b5745b8 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/context.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/context.rs @@ -170,6 +170,7 @@ impl<'a> FunctionContext<'a> { ast::Type::Tuple(fields) => { Tree::Branch(vecmap(fields, |field| Self::map_type_helper(field, f))) } + ast::Type::Unit => Tree::empty(), other => Tree::Leaf(f(Self::convert_non_tuple_type(other))), } } @@ -197,7 +198,7 @@ impl<'a> FunctionContext<'a> { ast::Type::Integer(Signedness::Unsigned, bits) => Type::unsigned(*bits), ast::Type::Bool => Type::unsigned(1), ast::Type::String(_) => Type::Reference, - ast::Type::Unit => Type::Unit, + ast::Type::Unit => panic!("convert_non_tuple_type called on a unit type"), ast::Type::Tuple(_) => panic!("convert_non_tuple_type called on a tuple: {typ}"), ast::Type::Function(_, _) => Type::Function, @@ -208,10 +209,9 @@ impl<'a> FunctionContext<'a> { } } - /// Insert a unit constant into the current function if not already - /// present, and return its value - pub(super) fn unit_value(&mut self) -> Values { - self.builder.numeric_constant(0u128, Type::Unit).into() + /// Returns the unit value, represented as an empty tree of values + pub(super) fn unit_value() -> Values { + Values::empty() } /// Insert a binary instruction at the end of the current block. diff --git a/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/mod.rs b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/mod.rs index 3694424b8b0..0dc003dd9de 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/mod.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/mod.rs @@ -153,7 +153,7 @@ impl<'a> FunctionContext<'a> { } fn codegen_block(&mut self, block: &[Expression]) -> Values { - let mut result = self.unit_value(); + let mut result = Self::unit_value(); for expr in block { result = self.codegen_expression(expr); } @@ -260,7 +260,7 @@ impl<'a> FunctionContext<'a> { // Finish by switching back to the end of the loop self.builder.switch_to_block(loop_end); - self.unit_value() + Self::unit_value() } /// Codegens an if expression, handling the case of what to do if there is no 'else'. @@ -298,7 +298,7 @@ impl<'a> FunctionContext<'a> { self.builder.switch_to_block(then_block); let then_value = self.codegen_expression(&if_expr.consequence); - let mut result = self.unit_value(); + let mut result = Self::unit_value(); if let Some(alternative) = &if_expr.alternative { let end_block = self.builder.insert_block(); @@ -364,13 +364,13 @@ impl<'a> FunctionContext<'a> { } self.define(let_expr.id, values); - self.unit_value() + Self::unit_value() } fn codegen_constrain(&mut self, expr: &Expression, _location: Location) -> Values { let boolean = self.codegen_non_tuple_expression(expr); self.builder.insert_constrain(boolean); - self.unit_value() + Self::unit_value() } fn codegen_assign(&mut self, assign: &ast::Assign) -> Values { @@ -378,11 +378,11 @@ impl<'a> FunctionContext<'a> { let rhs = self.codegen_expression(&assign.expression); self.assign_new_value(lhs, rhs); - self.unit_value() + Self::unit_value() } fn codegen_semi(&mut self, expr: &Expression) -> Values { self.codegen_expression(expr); - self.unit_value() + Self::unit_value() } } diff --git a/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/value.rs b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/value.rs index 059f29a650a..c50abb9ca30 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/value.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/ssa_gen/value.rs @@ -63,6 +63,11 @@ impl Value { pub(super) type Values = Tree; impl Tree { + /// Returns an empty tree node represented by a Branch with no branches + pub(super) fn empty() -> Self { + Tree::Branch(vec![]) + } + /// Flattens the tree into a vector of each leaf value pub(super) fn flatten(self) -> Vec { match self {