From 4e233abbf8a4766088902af01b2affce89577e75 Mon Sep 17 00:00:00 2001 From: foldr Date: Fri, 28 Jul 2023 15:39:49 -0500 Subject: [PATCH 01/12] Remove unnecessary logging in release and remove forgotten debug prints (#38) --- circuit_passes/src/bucket_interpreter/env.rs | 2 +- circuit_passes/src/bucket_interpreter/mod.rs | 4 ++-- circuit_passes/src/passes/conditional_flattening.rs | 3 --- circuit_passes/src/passes/loop_unroll.rs | 2 +- circuit_passes/src/passes/memory.rs | 2 +- compiler/src/intermediate_representation/log_bucket.rs | 3 +-- 6 files changed, 6 insertions(+), 10 deletions(-) diff --git a/circuit_passes/src/bucket_interpreter/env.rs b/circuit_passes/src/bucket_interpreter/env.rs index e91862182..b8df48402 100644 --- a/circuit_passes/src/bucket_interpreter/env.rs +++ b/circuit_passes/src/bucket_interpreter/env.rs @@ -264,7 +264,7 @@ impl<'a> Env<'a> { interpreter: &BucketInterpreter, args: Vec, observe: bool) -> Value { - println!("Running {}", name); + if cfg!(debug_assertions) { println!("Running {}", name); } let code = &self.functions_library[name].body; let mut function_env = Env::new(self.templates_library, self.functions_library, self.context_switcher); for (id, arg) in args.iter().enumerate() { diff --git a/circuit_passes/src/bucket_interpreter/mod.rs b/circuit_passes/src/bucket_interpreter/mod.rs index 7e1e1e1ee..670a8249a 100644 --- a/circuit_passes/src/bucket_interpreter/mod.rs +++ b/circuit_passes/src/bucket_interpreter/mod.rs @@ -496,12 +496,12 @@ impl<'a> BucketInterpreter<'a> { (None, None, env) } Some(true) => { - println!("Running then branch"); + if cfg!(debug_assertions) { println!("Running then branch"); } let (ret, env) = self.execute_instructions(&true_branch, env, observe); (ret, Some(true), env) } Some(false) => { - println!("Running else branch"); + if cfg!(debug_assertions) { println!("Running else branch"); } let (ret, env) = self.execute_instructions(&false_branch, env, observe); (ret, Some(false), env) } diff --git a/circuit_passes/src/passes/conditional_flattening.rs b/circuit_passes/src/passes/conditional_flattening.rs index cde287c6d..fbf84c67e 100644 --- a/circuit_passes/src/passes/conditional_flattening.rs +++ b/circuit_passes/src/passes/conditional_flattening.rs @@ -39,8 +39,6 @@ impl InterpreterObserver for ConditionalFlattening { } fn on_store_bucket(&self, bucket: &StoreBucket, env: &Env) -> bool { - println!("Before env: {}", env); - println!("on_store_bucket: {}", bucket.to_sexp().to_pretty(200)); true } @@ -65,7 +63,6 @@ impl InterpreterObserver for ConditionalFlattening { } fn on_block_bucket(&self, bucket: &BlockBucket, _env: &Env) -> bool { - println!("on_block_bucket({}): n_iters = {}", bucket.id, bucket.n_iters); true } diff --git a/circuit_passes/src/passes/loop_unroll.rs b/circuit_passes/src/passes/loop_unroll.rs index c66423488..9b5b77048 100644 --- a/circuit_passes/src/passes/loop_unroll.rs +++ b/circuit_passes/src/passes/loop_unroll.rs @@ -198,7 +198,7 @@ mod test { circuit.llvm_data.signal_index_mapping.insert("test_0".to_string(), HashMap::new()); circuit.llvm_data.component_index_mapping.insert("test_0".to_string(), HashMap::new()); let new_circuit = pass.transform_circuit(&circuit); - println!("{}", new_circuit.templates[0].body.last().unwrap().to_string()); + if cfg!(debug_assertions) { println!("{}", new_circuit.templates[0].body.last().unwrap().to_string()); } assert_ne!(circuit, new_circuit); match new_circuit.templates[0].body.last().unwrap().as_ref() { Instruction::Block(b) => assert_eq!(b.body.len(), 10), // 5 iterations unrolled times 2 statements in the loop body diff --git a/circuit_passes/src/passes/memory.rs b/circuit_passes/src/passes/memory.rs index 8ef1ce2d5..759f8c01e 100644 --- a/circuit_passes/src/passes/memory.rs +++ b/circuit_passes/src/passes/memory.rs @@ -43,7 +43,7 @@ impl PassMemory { pub fn run_template(&self, observer: &dyn InterpreterObserver, template: &TemplateCode) { assert!(!self.current_scope.is_empty()); - println!("Running {}", self.current_scope); + if cfg!(debug_assertions) { println!("Running {}", self.current_scope); } let interpreter = self.build_interpreter(observer); let env = Env::new(&self.templates_library, &self.functions_library, self); interpreter.execute_instructions(&template.body, env, true); diff --git a/compiler/src/intermediate_representation/log_bucket.rs b/compiler/src/intermediate_representation/log_bucket.rs index c0700a340..1e662d894 100644 --- a/compiler/src/intermediate_representation/log_bucket.rs +++ b/compiler/src/intermediate_representation/log_bucket.rs @@ -99,8 +99,7 @@ impl UpdateId for LogBucket { impl WriteLLVMIR for LogBucket { fn produce_llvm_ir<'a, 'b>(&self, producer: &'b dyn LLVMIRProducer<'a>) -> Option> { Self::manage_debug_loc_from_curr(producer, self); - - todo!() + None // Ignore this statements } } From 85480caa66a4ec6d95f3d431b53adf6e756867c3 Mon Sep 17 00:00:00 2001 From: Timothy Hoffman <4001421+tim-hoffman@users.noreply.github.com> Date: Wed, 9 Aug 2023 16:25:42 -0500 Subject: [PATCH 02/12] Cleanup code (#39) * fix compiler warnings (including removing a few unused functions) * apply auto-formatting in a few files * update 'lalrpop' dependency version to fix warning --- Cargo.lock | 497 +++++------------- circom/tests/lit.rs | 3 +- circuit_passes/src/bucket_interpreter/env.rs | 137 ++--- circuit_passes/src/bucket_interpreter/mod.rs | 20 +- .../src/bucket_interpreter/value.rs | 67 +-- circuit_passes/src/passes/checks.rs | 3 +- .../src/passes/conditional_flattening.rs | 15 +- .../deterministic_subcomponent_invocation.rs | 10 +- circuit_passes/src/passes/loop_unroll.rs | 23 +- .../src/passes/mapped_to_indexed.rs | 6 +- circuit_passes/src/passes/memory.rs | 44 +- circuit_passes/src/passes/mod.rs | 28 +- circuit_passes/src/passes/simplification.rs | 26 +- .../src/passes/unknown_index_sanitization.rs | 77 +-- .../src/llvm_elements/array_switch.rs | 54 +- code_producers/src/llvm_elements/functions.rs | 5 +- code_producers/src/llvm_elements/template.rs | 6 +- compiler/src/circuit_design/build.rs | 8 +- .../block_bucket.rs | 1 - .../call_bucket.rs | 1 - .../intermediate_representation/translate.rs | 12 +- parser/Cargo.toml | 4 +- parser/src/lib.rs | 4 +- parser/src/syntax_sugar_remover.rs | 4 +- summary/Cargo.toml | 3 + summary/src/lib.rs | 64 +-- 26 files changed, 416 insertions(+), 706 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f8e93bd3..8fac819e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,12 +41,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - [[package]] name = "arrayvec" version = "0.5.2" @@ -55,9 +49,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "ascii-canvas" -version = "2.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff8eb72df928aafb99fe5d37b383f2fe25bd2a765e3e5f7c365916b6f2463a29" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" dependencies = [ "term", ] @@ -117,12 +111,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "bit-set" version = "0.5.3" @@ -145,27 +133,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" +name = "bitflags" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "block-buffer" @@ -173,16 +144,7 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", + "generic-array", ] [[package]] @@ -196,12 +158,6 @@ dependencies = [ "serde", ] -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "byteorder" version = "1.4.3" @@ -275,22 +231,13 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", - "strsim 0.8.0", + "bitflags 1.3.2", + "strsim", "textwrap", "unicode-width", "vec_map", ] -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - [[package]] name = "code_producers" version = "2.1.3" @@ -338,12 +285,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "constant_tracking" version = "2.0.0" @@ -393,13 +334,10 @@ dependencies = [ ] [[package]] -name = "crossbeam-utils" -version = "0.8.16" +name = "crunchy" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" @@ -407,7 +345,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.7", + "generic-array", "typenum", ] @@ -436,28 +374,29 @@ checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" -version = "0.8.1" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "generic-array 0.12.4", + "block-buffer", + "crypto-common", ] [[package]] -name = "digest" -version = "0.10.7" +name = "dirs-next" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "block-buffer 0.10.4", - "crypto-common", + "cfg-if", + "dirs-sys-next", ] [[package]] -name = "dirs" -version = "1.0.5" +name = "dirs-sys-next" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", @@ -470,18 +409,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" -[[package]] -name = "docopt" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f3f119846c823f9eafcf953a8f6ffb6ed69bf6240883261a7f13b634579a51f" -dependencies = [ - "lazy_static", - "regex", - "serde", - "strsim 0.10.0", -] - [[package]] name = "either" version = "1.8.1" @@ -490,9 +417,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "ena" -version = "0.13.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" dependencies = [ "log", ] @@ -524,12 +451,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193" -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - [[package]] name = "fastrand" version = "1.9.0" @@ -541,9 +462,9 @@ dependencies = [ [[package]] name = "fixedbitset" -version = "0.1.9" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "float-cmp" @@ -560,12 +481,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - [[package]] name = "gcollections" version = "1.5.0" @@ -578,15 +493,6 @@ dependencies = [ "trilean", ] -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -644,7 +550,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "ignore", "walkdir", ] @@ -663,6 +569,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -695,6 +607,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg 1.1.0", + "hashbrown", +] + [[package]] name = "inkwell" version = "0.1.1" @@ -752,12 +674,14 @@ dependencies = [ ] [[package]] -name = "itertools" -version = "0.8.2" +name = "is-terminal" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "either", + "hermit-abi 0.3.2", + "rustix 0.38.7", + "windows-sys", ] [[package]] @@ -783,34 +707,32 @@ checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" [[package]] name = "lalrpop" -version = "0.18.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de5e019883a6e9734d093f34216a3857160c6bc2a9a1ec196a177aaa737c74af" +checksum = "da4081d44f4611b66c6dd725e6de3169f9f63905421e8626fcb86b6a898998b8" dependencies = [ "ascii-canvas", - "atty", "bit-set", "diff", - "docopt", "ena", - "itertools 0.8.2", + "is-terminal", + "itertools", "lalrpop-util", "petgraph", + "pico-args", "regex", - "regex-syntax 0.6.29", - "serde", - "serde_derive", - "sha2 0.8.2", + "regex-syntax", "string_cache", "term", + "tiny-keccak", "unicode-xid", ] [[package]] name = "lalrpop-util" -version = "0.18.1" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d6e9bc1801eb54529fd6a020aaf9514e8193bb6b42d96d0fe7da99187efa93d" +checksum = "3f35c735096c0293d313e8f2a641627472b83d01b937177fe76e5e2708d31e0d" dependencies = [ "regex", ] @@ -848,6 +770,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" + [[package]] name = "llvm-sys" version = "130.1.1" @@ -965,18 +893,6 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "ordermap" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" - [[package]] name = "parking_lot" version = "0.12.1" @@ -1056,37 +972,33 @@ checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" dependencies = [ "once_cell", "pest", - "sha2 0.10.7", + "sha2", ] [[package]] name = "petgraph" -version = "0.4.13" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" +checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" dependencies = [ "fixedbitset", - "ordermap", + "indexmap", ] [[package]] -name = "phf_generator" -version = "0.7.24" +name = "phf_shared" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" dependencies = [ - "phf_shared", - "rand 0.6.5", + "siphasher", ] [[package]] -name = "phf_shared" -version = "0.7.24" +name = "pico-args" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" -dependencies = [ - "siphasher", -] +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "ppv-lite86" @@ -1107,7 +1019,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" dependencies = [ "difflib", - "itertools 0.10.5", + "itertools", "predicates-core", ] @@ -1120,7 +1032,7 @@ dependencies = [ "anstyle 1.0.1", "difflib", "float-cmp", - "itertools 0.10.5", + "itertools", "normalize-line-endings", "predicates-core", "regex", @@ -1185,25 +1097,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi", -] - [[package]] name = "rand" version = "0.7.3" @@ -1214,7 +1107,7 @@ dependencies = [ "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", - "rand_hc 0.2.0", + "rand_hc", ] [[package]] @@ -1228,16 +1121,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", -] - [[package]] name = "rand_chacha" version = "0.2.2" @@ -1258,21 +1141,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - [[package]] name = "rand_core" version = "0.5.1" @@ -1291,15 +1159,6 @@ dependencies = [ "getrandom 0.2.10", ] -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "rand_hc" version = "0.2.0" @@ -1310,91 +1169,32 @@ dependencies = [ ] [[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rdrand" -version = "0.4.0" +name = "redox_syscall" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "rand_core 0.3.1", + "bitflags 1.3.2", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "redox_users" -version = "0.3.5" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", + "getrandom 0.2.10", + "redox_syscall 0.2.16", + "thiserror", ] [[package]] @@ -1406,7 +1206,7 @@ dependencies = [ "aho-corasick 1.0.2", "memchr", "regex-automata", - "regex-syntax 0.7.4", + "regex-syntax", ] [[package]] @@ -1417,33 +1217,15 @@ checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" dependencies = [ "aho-corasick 1.0.2", "memchr", - "regex-syntax 0.7.4", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - [[package]] name = "rustc-hex" version = "2.1.0" @@ -1456,14 +1238,33 @@ version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399" +dependencies = [ + "bitflags 2.3.3", + "errno", + "libc", + "linux-raw-sys 0.4.5", "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.14" @@ -1534,18 +1335,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug", -] - [[package]] name = "sha2" version = "0.10.7" @@ -1554,14 +1343,14 @@ checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] name = "siphasher" -version = "0.2.3" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "smallvec" @@ -1577,50 +1366,23 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "string_cache" -version = "0.7.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89c058a82f9fd69b1becf8c274f412281038877c553182f1d02eb027045a2d67" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ - "lazy_static", "new_debug_unreachable", + "once_cell", + "parking_lot", "phf_shared", "precomputed-hash", - "serde", - "string_cache_codegen", - "string_cache_shared", -] - -[[package]] -name = "string_cache_codegen" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f45ed1b65bf9a4bf2f7b7dc59212d1926e9eaf00fa998988e420fd124467c6" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2", - "quote", - "string_cache_shared", ] -[[package]] -name = "string_cache_shared" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" - [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "summary" version = "2.1.3" @@ -1665,18 +1427,18 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall 0.3.5", - "rustix", + "rustix 0.37.23", "windows-sys", ] [[package]] name = "term" -version = "0.5.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ - "byteorder", - "dirs", + "dirs-next", + "rustversion", "winapi", ] @@ -1743,6 +1505,15 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "trilean" version = "1.1.0" diff --git a/circom/tests/lit.rs b/circom/tests/lit.rs index ad9a24e84..711f23517 100644 --- a/circom/tests/lit.rs +++ b/circom/tests/lit.rs @@ -2,9 +2,8 @@ use std::fs; use std::fs::File; use std::path::{Path, PathBuf}; use assert_cmd::Command; -use assert_fs::fixture::ChildPath; use assert_fs::NamedTempFile; -use assert_fs::prelude::{FileTouch, FileWriteStr, PathChild}; +use assert_fs::prelude::FileWriteStr; use lazy_static::lazy_static; use regex::Regex; use rand::{distributions::Alphanumeric, Rng}; // 0.8 diff --git a/circuit_passes/src/bucket_interpreter/env.rs b/circuit_passes/src/bucket_interpreter/env.rs index b8df48402..7c584ff7c 100644 --- a/circuit_passes/src/bucket_interpreter/env.rs +++ b/circuit_passes/src/bucket_interpreter/env.rs @@ -1,19 +1,19 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; -use code_producers::llvm_elements::instructions::create_phi; - use compiler::circuit_design::function::FunctionCode; use compiler::circuit_design::template::TemplateCode; +use crate::bucket_interpreter::BucketInterpreter; +use crate::bucket_interpreter::value::{JoinSemiLattice, Value}; pub type TemplatesLibrary = HashMap; pub type FunctionsLibrary = HashMap; -use crate::bucket_interpreter::BucketInterpreter; -use crate::bucket_interpreter::observer::InterpreterObserver; -use crate::bucket_interpreter::value::{JoinSemiLattice, Value}; - pub trait ContextSwitcher { - fn switch<'a>(&'a self, interpreter: &'a BucketInterpreter<'a>, scope: &'a String) -> BucketInterpreter<'a>; + fn switch<'a>( + &'a self, + interpreter: &'a BucketInterpreter<'a>, + scope: &'a String, + ) -> BucketInterpreter<'a>; } impl JoinSemiLattice for HashMap { @@ -39,7 +39,7 @@ pub struct SubcmpEnv<'a> { pub signals: HashMap, counter: usize, name: &'a String, - template_id: usize + template_id: usize, } impl JoinSemiLattice for SubcmpEnv<'_> { @@ -50,7 +50,7 @@ impl JoinSemiLattice for SubcmpEnv<'_> { signals: self.signals.join(&other.signals), counter: std::cmp::min(self.counter, other.counter), name: self.name, - template_id: self.template_id + template_id: self.template_id, } } } @@ -76,12 +76,6 @@ impl<'a> SubcmpEnv<'a> { copy } - pub fn set_signals(self, signals: HashMap) -> SubcmpEnv<'a> { - let mut copy = self; - copy.signals = signals; - copy - } - pub fn counter_is_zero(&self) -> bool { self.counter == 0 } @@ -97,37 +91,6 @@ impl<'a> SubcmpEnv<'a> { } } -// /// Very inefficient -// #[derive(Default)] -// pub struct EnvSet<'a> { -// envs: Vec> -// } -// -// impl EnvSet<'_> { -// pub fn new() -> Self { -// EnvSet { -// envs: Default::default() -// } -// } -// -// pub fn contains(&self, env: &Env) -> bool { -// for e in &self.envs { -// if e == env { -// return true; -// } -// } -// false -// } -// -// pub fn add(&self, env: &Env) -> EnvSet { -// let mut new = vec![env.clone()]; -// for e in &self.envs { -// new.push(e.clone()) -// } -// EnvSet { envs: new } -// } -// } - // An immutable env that returns a new copy when modified #[derive(Clone)] pub struct Env<'a> { @@ -136,24 +99,32 @@ pub struct Env<'a> { subcmps: HashMap>, templates_library: &'a TemplatesLibrary, functions_library: &'a FunctionsLibrary, - context_switcher: &'a dyn ContextSwitcher + context_switcher: &'a dyn ContextSwitcher, } impl Display for Env<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "\n vars = {:?}\n signals = {:?}\n subcmps = {:?}", self.vars, self.signals, self.subcmps) + write!( + f, + "\n vars = {:?}\n signals = {:?}\n subcmps = {:?}", + self.vars, self.signals, self.subcmps + ) } } impl<'a> Env<'a> { - pub fn new(templates_library: &'a TemplatesLibrary, functions_library: &'a FunctionsLibrary, context_switcher: &'a dyn ContextSwitcher) -> Self { + pub fn new( + templates_library: &'a TemplatesLibrary, + functions_library: &'a FunctionsLibrary, + context_switcher: &'a dyn ContextSwitcher, + ) -> Self { Env { vars: Default::default(), signals: Default::default(), subcmps: Default::default(), templates_library, functions_library, - context_switcher + context_switcher, } } @@ -193,12 +164,6 @@ impl<'a> Env<'a> { copy } - pub fn set_signals(self, signals: HashMap) -> Self { - let mut copy = self; - copy.signals = signals; - copy - } - pub fn set_signal(self, idx: usize, value: Value) -> Self { let mut copy = self; copy.signals.insert(idx, value); @@ -208,7 +173,10 @@ impl<'a> Env<'a> { /// Sets all the signals of the subcmp to UNK pub fn set_subcmp_to_unk(self, subcmp_idx: usize) -> Self { let mut copy = self; - let subcmp_env = copy.subcmps.remove(&subcmp_idx).expect(format!("Can't set a signal of subcomponent {}", subcmp_idx).as_str()); + let subcmp_env = copy + .subcmps + .remove(&subcmp_idx) + .expect(format!("Can't set a signal of subcomponent {}", subcmp_idx).as_str()); copy.subcmps.insert(subcmp_idx, subcmp_env.reset()); copy } @@ -216,25 +184,24 @@ impl<'a> Env<'a> { pub fn set_subcmp_signal(self, subcmp_idx: usize, signal_idx: usize, value: Value) -> Self { //let subcmp = &self.subcmps[&subcmp_idx]; let mut copy = self; - let subcmp_env = copy.subcmps.remove(&subcmp_idx).expect(format!("Can't set a signal of subcomponent {}", subcmp_idx).as_str()); + let subcmp_env = copy + .subcmps + .remove(&subcmp_idx) + .expect(format!("Can't set a signal of subcomponent {}", subcmp_idx).as_str()); copy.subcmps.insert(subcmp_idx, subcmp_env.set_signal(signal_idx, value)); copy } pub fn decrease_subcmp_counter(self, subcmp_idx: usize) -> Self { let mut copy = self; - let subcmp_env = copy.subcmps.remove(&subcmp_idx).expect(format!("Can't decrease counter of subcomponent {}", subcmp_idx).as_str()); + let subcmp_env = copy + .subcmps + .remove(&subcmp_idx) + .expect(format!("Can't decrease counter of subcomponent {}", subcmp_idx).as_str()); copy.subcmps.insert(subcmp_idx, subcmp_env.decrease_counter()); copy } - pub fn set_subcmp_signals(self, subcmp_idx: usize, signals: HashMap) -> Self { - let mut copy = self; - let subcmp_env = copy.subcmps.remove(&subcmp_idx).expect(format!("Can't decrease counter of subcomponent {}", subcmp_idx).as_str()); - copy.subcmps.insert(subcmp_idx, subcmp_env.set_signals(signals)); - copy - } - pub fn run_subcmp( self, _subcmp_idx: usize, @@ -248,25 +215,34 @@ impl<'a> Env<'a> { self } - pub fn create_subcmp(self, name: &'a String, base_index: usize, count: usize, template_id: usize) -> Self { - let number_of_inputs = { - self.templates_library[name].number_of_inputs - }; + pub fn create_subcmp( + self, + name: &'a String, + base_index: usize, + count: usize, + template_id: usize, + ) -> Self { + let number_of_inputs = { self.templates_library[name].number_of_inputs }; let mut copy = self; for i in base_index..(base_index + count) { - copy.subcmps - .insert(i, SubcmpEnv::new(number_of_inputs, name, template_id)); + copy.subcmps.insert(i, SubcmpEnv::new(number_of_inputs, name, template_id)); } copy } - pub fn run_function(&self, name: &String, - interpreter: &BucketInterpreter, - args: Vec, - observe: bool) -> Value { - if cfg!(debug_assertions) { println!("Running {}", name); } + pub fn run_function( + &self, + name: &String, + interpreter: &BucketInterpreter, + args: Vec, + observe: bool, + ) -> Value { + if cfg!(debug_assertions) { + println!("Running {}", name); + } let code = &self.functions_library[name].body; - let mut function_env = Env::new(self.templates_library, self.functions_library, self.context_switcher); + let mut function_env = + Env::new(self.templates_library, self.functions_library, self.context_switcher); for (id, arg) in args.iter().enumerate() { function_env = function_env.set_var(id, arg.clone()); } @@ -274,7 +250,8 @@ impl<'a> Env<'a> { let r = interpreter.execute_instructions( &code, function_env, - !interpreter.observer.ignore_function_calls() && observe); + !interpreter.observer.ignore_function_calls() && observe, + ); r.0.expect("Function must return a value!") } @@ -285,7 +262,7 @@ impl<'a> Env<'a> { subcmps: self.subcmps.join(&other.subcmps), templates_library: self.templates_library, functions_library: self.functions_library, - context_switcher: self.context_switcher + context_switcher: self.context_switcher, } } } diff --git a/circuit_passes/src/bucket_interpreter/mod.rs b/circuit_passes/src/bucket_interpreter/mod.rs index 670a8249a..3c82cc7fe 100644 --- a/circuit_passes/src/bucket_interpreter/mod.rs +++ b/circuit_passes/src/bucket_interpreter/mod.rs @@ -3,24 +3,22 @@ pub mod env; pub mod observer; pub(crate) mod operations; -use std::collections::HashMap; -use std::ops::{Range, RangeInclusive}; use circom_algebra::modular_arithmetic; use code_producers::components::TemplateInstanceIOMap; use code_producers::llvm_elements::IndexMapping; -use compiler::intermediate_representation::{Instruction, InstructionList, InstructionPointer, ToSExp}; -use compiler::intermediate_representation::ir_interface::{AddressType, AssertBucket, BlockBucket, BranchBucket, CallBucket, ComputeBucket, ConstraintBucket, CreateCmpBucket, InputInformation, LoadBucket, LocationRule, LogBucket, LogBucketArg, LoopBucket, NopBucket, OperatorType, ReturnBucket, ReturnType, StatusInput, StoreBucket, ValueBucket, ValueType}; +use compiler::intermediate_representation::{Instruction, InstructionList, InstructionPointer}; +use compiler::intermediate_representation::ir_interface::*; use compiler::num_bigint::BigInt; use observer::InterpreterObserver; use program_structure::constants::UsefulConstants; use crate::bucket_interpreter::env::Env; -use crate::bucket_interpreter::value::{JoinSemiLattice, mod_value, resolve_operation, Value}; +use crate::bucket_interpreter::value::{JoinSemiLattice, Value}; use crate::bucket_interpreter::value::Value::{KnownBigInt, KnownU32, Unknown}; pub struct BucketInterpreter<'a> { - scope: &'a String, - prime: &'a String, + _scope: &'a String, + _prime: &'a String, pub constant_fields: &'a Vec, pub(crate) observer: &'a dyn InterpreterObserver, io_map: &'a TemplateInstanceIOMap, @@ -61,8 +59,8 @@ impl<'a> BucketInterpreter<'a> { component_addr_index_mapping: &'a IndexMapping ) -> Self { BucketInterpreter { - scope, - prime, + _scope: scope, + _prime: prime, constant_fields, observer, io_map, @@ -184,10 +182,6 @@ impl<'a> BucketInterpreter<'a> { return (vars, signals, subcmps); } - pub fn clone_in_new_scope(interpreter: &Self, new_scope: &'a String) -> BucketInterpreter<'a> { - Self::init(new_scope, interpreter.prime, interpreter.constant_fields, interpreter.observer, interpreter.io_map, &interpreter.signal_index_mapping, &interpreter.variables_index_mapping, &interpreter.component_addr_index_mapping) - } - pub fn execute_value_bucket<'env>(&self, bucket: &ValueBucket, env: Env<'env>, _observe: bool) -> R<'env> { ( Some(match bucket.parse_as { diff --git a/circuit_passes/src/bucket_interpreter/value.rs b/circuit_passes/src/bucket_interpreter/value.rs index b85ba24ac..3d6b1dd44 100644 --- a/circuit_passes/src/bucket_interpreter/value.rs +++ b/circuit_passes/src/bucket_interpreter/value.rs @@ -1,10 +1,10 @@ use std::fmt::{Display, Formatter}; use compiler::intermediate_representation::ir_interface::{ValueBucket, ValueType}; use compiler::num_bigint::BigInt; -use compiler::num_traits::{One, ToPrimitive, Zero}; +use compiler::num_traits::ToPrimitive; +use compiler::intermediate_representation::new_id; use circom_algebra::modular_arithmetic; use circom_algebra::modular_arithmetic::ArithmeticError; -use compiler::intermediate_representation::new_id; use crate::bucket_interpreter::value::Value::{KnownBigInt, KnownU32, Unknown}; pub trait JoinSemiLattice { @@ -35,7 +35,11 @@ impl JoinSemiLattice for Value { /// a ⊔ b = a iff a = b /// a ⊔ b = UNK otherwise fn join(&self, other: &Self) -> Self { - if self == other { self.clone() } else { Unknown } + if self == other { + self.clone() + } else { + Unknown + } } } @@ -72,9 +76,7 @@ impl Value { match self { KnownU32(0) => false, KnownU32(1) => true, - KnownBigInt(n) => { - modular_arithmetic::as_bool(n, field) - } + KnownBigInt(n) => modular_arithmetic::as_bool(n, field), _ => panic!( "Attempted to convert a value that cannot be converted to boolean! {:?}", self @@ -118,15 +120,19 @@ fn wrap_op( rhs: &Value, field: &BigInt, u32_op: impl Fn(&usize, &usize) -> usize, - bigint_op: impl Fn(&BigInt, &BigInt, &BigInt) -> BigInt + bigint_op: impl Fn(&BigInt, &BigInt, &BigInt) -> BigInt, ) -> Value { match (lhs, rhs) { (Unknown, _) => Unknown, (_, Unknown) => Unknown, (KnownU32(lhs), KnownU32(rhs)) => KnownU32(u32_op(lhs, rhs)), - (KnownU32(lhs), KnownBigInt(rhs)) => KnownBigInt(bigint_op(&BigInt::from(*lhs), rhs, field)), + (KnownU32(lhs), KnownBigInt(rhs)) => { + KnownBigInt(bigint_op(&BigInt::from(*lhs), rhs, field)) + } (KnownBigInt(lhs), KnownBigInt(rhs)) => KnownBigInt(bigint_op(lhs, rhs, field)), - (KnownBigInt(lhs), KnownU32(rhs)) => KnownBigInt(bigint_op(lhs, &BigInt::from(*rhs), field)), + (KnownBigInt(lhs), KnownU32(rhs)) => { + KnownBigInt(bigint_op(lhs, &BigInt::from(*rhs), field)) + } } } @@ -136,15 +142,21 @@ fn wrap_op_result( rhs: &Value, field: &BigInt, u32_op: impl Fn(&usize, &usize) -> usize, - bigint_op: impl Fn(&BigInt, &BigInt, &BigInt) -> Result + bigint_op: impl Fn(&BigInt, &BigInt, &BigInt) -> Result, ) -> Value { match (lhs, rhs) { (Unknown, _) => Unknown, (_, Unknown) => Unknown, (KnownU32(lhs), KnownU32(rhs)) => KnownU32(u32_op(lhs, rhs)), - (KnownU32(lhs), KnownBigInt(rhs)) => KnownBigInt(bigint_op(&BigInt::from(*lhs), rhs, field).ok().unwrap()), - (KnownBigInt(lhs), KnownBigInt(rhs)) => KnownBigInt(bigint_op(lhs, rhs, field).ok().unwrap()), - (KnownBigInt(lhs), KnownU32(rhs)) => KnownBigInt(bigint_op(lhs, &BigInt::from(*rhs), field).ok().unwrap()), + (KnownU32(lhs), KnownBigInt(rhs)) => { + KnownBigInt(bigint_op(&BigInt::from(*lhs), rhs, field).ok().unwrap()) + } + (KnownBigInt(lhs), KnownBigInt(rhs)) => { + KnownBigInt(bigint_op(lhs, rhs, field).ok().unwrap()) + } + (KnownBigInt(lhs), KnownU32(rhs)) => { + KnownBigInt(bigint_op(lhs, &BigInt::from(*rhs), field).ok().unwrap()) + } } } @@ -158,27 +170,12 @@ pub fn sub_value(lhs: &Value, rhs: &Value, field: &BigInt) -> Value { pub fn mul_value(lhs: &Value, rhs: &Value, field: &BigInt) -> Value { wrap_op(lhs, rhs, field, |x, y| x * y, modular_arithmetic::mul) - } pub fn div_value(lhs: &Value, rhs: &Value, field: &BigInt) -> Value { wrap_op_result(lhs, rhs, field, |x, y| x / y, modular_arithmetic::div) } -fn fr_pow(lhs: &BigInt, rhs: &BigInt) -> BigInt { - let abv: BigInt = if rhs < &BigInt::from(0) { -rhs.clone() } else { rhs.clone() }; - let mut res = BigInt::from(1); - let mut i = BigInt::from(0); - while i < abv { - res *= lhs; - i += 1 - } - if rhs < &BigInt::from(0) { - res = 1 / res; - } - res -} - pub fn pow_value(lhs: &Value, rhs: &Value, field: &BigInt) -> Value { wrap_op(lhs, rhs, field, |x, y| x.pow(*y as u32), modular_arithmetic::pow) } @@ -247,7 +244,7 @@ pub fn prefix_sub(v: &Value, field: &BigInt) -> Value { match v { Unknown => Unknown, KnownU32(_n) => panic!("We cannot get the negative of an unsigned integer!"), - KnownBigInt(n) => KnownBigInt(modular_arithmetic::prefix_sub(n, field)) + KnownBigInt(n) => KnownBigInt(modular_arithmetic::prefix_sub(n, field)), } } @@ -262,9 +259,9 @@ pub fn complement(v: &Value, field: &BigInt) -> Value { pub fn to_address(v: &Value) -> Value { match v { Unknown => panic!("Cant convert into an address an unknown value!"), - KnownBigInt(b) => KnownU32(b.to_u64().expect(format!( - "Can't convert {} to a usize type", b - ).as_str()) as usize), + KnownBigInt(b) => KnownU32( + b.to_u64().expect(format!("Can't convert {} to a usize type", b).as_str()) as usize, + ), x => x.clone(), } } @@ -295,7 +292,11 @@ impl Default for &Value { } } -pub fn resolve_operation(op: fn(&Value, &Value, &BigInt) -> Value, p: &BigInt, stack: &[Value]) -> Value { +pub fn resolve_operation( + op: fn(&Value, &Value, &BigInt) -> Value, + p: &BigInt, + stack: &[Value], +) -> Value { assert!(stack.len() > 0); let mut acc = stack[0].clone(); for i in &stack[1..] { diff --git a/circuit_passes/src/passes/checks.rs b/circuit_passes/src/passes/checks.rs index 22b9f0c67..ccd0ba581 100644 --- a/circuit_passes/src/passes/checks.rs +++ b/circuit_passes/src/passes/checks.rs @@ -1,10 +1,9 @@ use std::collections::HashSet; -use std::ops::Add; use compiler::circuit_design::function::FunctionCode; use compiler::circuit_design::template::TemplateCode; use compiler::compiler_interface::Circuit; use compiler::intermediate_representation::{BucketId, Instruction, InstructionList, InstructionPointer}; -use compiler::intermediate_representation::ir_interface::{AddressType, LocationRule, LogBucketArg, ReturnType, ValueBucket}; +use compiler::intermediate_representation::ir_interface::{AddressType, LocationRule, LogBucketArg, ReturnType}; type Ids<'a> = &'a mut HashSet; diff --git a/circuit_passes/src/passes/conditional_flattening.rs b/circuit_passes/src/passes/conditional_flattening.rs index fbf84c67e..63ea9b185 100644 --- a/circuit_passes/src/passes/conditional_flattening.rs +++ b/circuit_passes/src/passes/conditional_flattening.rs @@ -2,14 +2,9 @@ use std::cell::RefCell; use std::collections::BTreeMap; use compiler::circuit_design::template::TemplateCode; use compiler::compiler_interface::Circuit; -use compiler::intermediate_representation::{InstructionPointer, new_id, ToSExp}; -use compiler::intermediate_representation::ir_interface::{ - Allocate, AssertBucket, BlockBucket, BranchBucket, CallBucket, ComputeBucket, ConstraintBucket, - CreateCmpBucket, LoadBucket, LocationRule, LogBucket, LoopBucket, NopBucket, ReturnBucket, - StoreBucket, ValueBucket, -}; +use compiler::intermediate_representation::{InstructionPointer, new_id}; +use compiler::intermediate_representation::ir_interface::*; use crate::bucket_interpreter::env::Env; -use crate::bucket_interpreter::BucketInterpreter; use crate::bucket_interpreter::observer::InterpreterObserver; use crate::passes::CircuitTransformationPass; use crate::passes::memory::PassMemory; @@ -38,7 +33,7 @@ impl InterpreterObserver for ConditionalFlattening { true } - fn on_store_bucket(&self, bucket: &StoreBucket, env: &Env) -> bool { + fn on_store_bucket(&self, _bucket: &StoreBucket, _env: &Env) -> bool { true } @@ -62,7 +57,7 @@ impl InterpreterObserver for ConditionalFlattening { true } - fn on_block_bucket(&self, bucket: &BlockBucket, _env: &Env) -> bool { + fn on_block_bucket(&self, _bucket: &BlockBucket, _env: &Env) -> bool { true } @@ -134,7 +129,7 @@ impl CircuitTransformationPass for ConditionalFlattening { line: bucket.line, message_id: bucket.message_id, body: code.clone(), - n_iters: 1 + n_iters: 1, }; return self.transform_block_bucket(&block); } diff --git a/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs b/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs index 26ccf352b..aa7fa6d30 100644 --- a/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs +++ b/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs @@ -1,17 +1,9 @@ use std::cell::RefCell; use std::collections::BTreeMap; - use compiler::circuit_design::template::TemplateCode; use compiler::compiler_interface::Circuit; - -use compiler::intermediate_representation::ir_interface::{ - AddressType, AssertBucket, BlockBucket, BranchBucket, CallBucket, ComputeBucket, - ConstraintBucket, CreateCmpBucket, InputInformation, LoadBucket, LocationRule, LogBucket, - LoopBucket, NopBucket, ReturnBucket, StatusInput, StoreBucket, ValueBucket, -}; +use compiler::intermediate_representation::ir_interface::*; use compiler::intermediate_representation::ir_interface::StatusInput::{Last, NoLast}; - -use crate::bucket_interpreter::BucketInterpreter; use crate::bucket_interpreter::env::Env; use crate::bucket_interpreter::observer::InterpreterObserver; use crate::passes::CircuitTransformationPass; diff --git a/circuit_passes/src/passes/loop_unroll.rs b/circuit_passes/src/passes/loop_unroll.rs index 9b5b77048..318b64dbc 100644 --- a/circuit_passes/src/passes/loop_unroll.rs +++ b/circuit_passes/src/passes/loop_unroll.rs @@ -1,17 +1,12 @@ use std::cell::RefCell; use std::collections::BTreeMap; - use compiler::circuit_design::template::TemplateCode; use compiler::compiler_interface::Circuit; -use compiler::intermediate_representation::{BucketId, InstructionList, InstructionPointer, new_id, ToSExp, UpdateId}; -use compiler::intermediate_representation::ir_interface::{ - Allocate, AssertBucket, BlockBucket, BranchBucket, CallBucket, ComputeBucket, ConstraintBucket, - CreateCmpBucket, LoadBucket, LocationRule, LogBucket, LoopBucket, NopBucket, ReturnBucket, - StoreBucket, ValueBucket, +use compiler::intermediate_representation::{ + BucketId, InstructionList, InstructionPointer, new_id, UpdateId, }; - +use compiler::intermediate_representation::ir_interface::*; use crate::bucket_interpreter::env::Env; -use crate::bucket_interpreter::BucketInterpreter; use crate::bucket_interpreter::observer::InterpreterObserver; use crate::passes::CircuitTransformationPass; use crate::passes::memory::PassMemory; @@ -20,12 +15,14 @@ pub struct LoopUnrollPass { // Wrapped in a RefCell because the reference to the static analysis is immutable but we need mutability memory: RefCell, replacements: RefCell>, - } impl LoopUnrollPass { pub fn new(prime: &String) -> Self { - LoopUnrollPass { memory: PassMemory::new_cell(prime, String::from(""), Default::default()), replacements: Default::default() } + LoopUnrollPass { + memory: PassMemory::new_cell(prime, String::from(""), Default::default()), + replacements: Default::default(), + } } fn try_unroll_loop(&self, bucket: &LoopBucket, env: &Env) -> (Option, usize) { @@ -93,7 +90,7 @@ impl InterpreterObserver for LoopUnrollPass { line: bucket.line, message_id: bucket.message_id, body: block_body, - n_iters + n_iters, }; self.continue_inside(&block, env); self.replacements.borrow_mut().insert(bucket.id, block.allocate()); @@ -198,7 +195,9 @@ mod test { circuit.llvm_data.signal_index_mapping.insert("test_0".to_string(), HashMap::new()); circuit.llvm_data.component_index_mapping.insert("test_0".to_string(), HashMap::new()); let new_circuit = pass.transform_circuit(&circuit); - if cfg!(debug_assertions) { println!("{}", new_circuit.templates[0].body.last().unwrap().to_string()); } + if cfg!(debug_assertions) { + println!("{}", new_circuit.templates[0].body.last().unwrap().to_string()); + } assert_ne!(circuit, new_circuit); match new_circuit.templates[0].body.last().unwrap().as_ref() { Instruction::Block(b) => assert_eq!(b.body.len(), 10), // 5 iterations unrolled times 2 statements in the loop body diff --git a/circuit_passes/src/passes/mapped_to_indexed.rs b/circuit_passes/src/passes/mapped_to_indexed.rs index d71f4ce5b..695c2f6d1 100644 --- a/circuit_passes/src/passes/mapped_to_indexed.rs +++ b/circuit_passes/src/passes/mapped_to_indexed.rs @@ -1,13 +1,9 @@ use std::cell::RefCell; use std::collections::BTreeMap; - use compiler::circuit_design::template::TemplateCode; use compiler::compiler_interface::Circuit; -use compiler::intermediate_representation::{InstructionPointer}; -use compiler::intermediate_representation::ir_interface::{AddressType, Allocate, AssertBucket, BlockBucket, BranchBucket, CallBucket, ComputeBucket, ConstraintBucket, CreateCmpBucket, LoadBucket, LocationRule, LogBucket, LoopBucket, NopBucket, ReturnBucket, StoreBucket, ValueBucket}; - +use compiler::intermediate_representation::ir_interface::*; use crate::bucket_interpreter::env::Env; -use crate::bucket_interpreter::BucketInterpreter; use crate::bucket_interpreter::observer::InterpreterObserver; use crate::bucket_interpreter::value::Value::KnownU32; use crate::passes::CircuitTransformationPass; diff --git a/circuit_passes/src/passes/memory.rs b/circuit_passes/src/passes/memory.rs index 759f8c01e..fc41322cf 100644 --- a/circuit_passes/src/passes/memory.rs +++ b/circuit_passes/src/passes/memory.rs @@ -19,11 +19,15 @@ pub struct PassMemory { pub io_map: TemplateInstanceIOMap, pub signal_index_mapping: HashMap, pub variables_index_mapping: HashMap, - pub component_addr_index_mapping: HashMap + pub component_addr_index_mapping: HashMap, } impl PassMemory { - pub fn new_cell(prime: &String, current_scope: String, io_map: TemplateInstanceIOMap) -> RefCell { + pub fn new_cell( + prime: &String, + current_scope: String, + io_map: TemplateInstanceIOMap, + ) -> RefCell { RefCell::new(PassMemory { templates_library: Default::default(), functions_library: Default::default(), @@ -33,7 +37,7 @@ impl PassMemory { io_map, signal_index_mapping: Default::default(), variables_index_mapping: Default::default(), - component_addr_index_mapping: Default::default() + component_addr_index_mapping: Default::default(), }) } @@ -43,18 +47,36 @@ impl PassMemory { pub fn run_template(&self, observer: &dyn InterpreterObserver, template: &TemplateCode) { assert!(!self.current_scope.is_empty()); - if cfg!(debug_assertions) { println!("Running {}", self.current_scope); } + if cfg!(debug_assertions) { + println!("Running {}", self.current_scope); + } let interpreter = self.build_interpreter(observer); let env = Env::new(&self.templates_library, &self.functions_library, self); interpreter.execute_instructions(&template.body, env, true); } - pub fn build_interpreter<'a>(&'a self, observer: &'a dyn InterpreterObserver) -> BucketInterpreter { + pub fn build_interpreter<'a>( + &'a self, + observer: &'a dyn InterpreterObserver, + ) -> BucketInterpreter { self.build_interpreter_with_scope(observer, &self.current_scope) } - fn build_interpreter_with_scope<'a>(&'a self, observer: &'a dyn InterpreterObserver, scope: &'a String) -> BucketInterpreter { - BucketInterpreter::init(scope, &self.prime, &self.constant_fields, observer, &self.io_map, &self.signal_index_mapping[scope], &self.variables_index_mapping[scope], &self.component_addr_index_mapping[scope]) + fn build_interpreter_with_scope<'a>( + &'a self, + observer: &'a dyn InterpreterObserver, + scope: &'a String, + ) -> BucketInterpreter { + BucketInterpreter::init( + scope, + &self.prime, + &self.constant_fields, + observer, + &self.io_map, + &self.signal_index_mapping[scope], + &self.variables_index_mapping[scope], + &self.component_addr_index_mapping[scope], + ) } pub fn add_template(&mut self, template: &TemplateCode) { @@ -81,7 +103,11 @@ impl PassMemory { } impl ContextSwitcher for PassMemory { - fn switch<'a>(&'a self, interpreter: &'a BucketInterpreter<'a>, scope: &'a String) -> BucketInterpreter<'a> { + fn switch<'a>( + &'a self, + interpreter: &'a BucketInterpreter<'a>, + scope: &'a String, + ) -> BucketInterpreter<'a> { self.build_interpreter_with_scope(interpreter.observer, scope) } -} \ No newline at end of file +} diff --git a/circuit_passes/src/passes/mod.rs b/circuit_passes/src/passes/mod.rs index aba7457d4..7aef0c06c 100644 --- a/circuit_passes/src/passes/mod.rs +++ b/circuit_passes/src/passes/mod.rs @@ -1,25 +1,14 @@ -use code_producers::llvm_elements::LLVMCircuitData; +use std::cell::RefCell; use compiler::circuit_design::function::{FunctionCode, FunctionCodeInfo}; use compiler::circuit_design::template::{TemplateCode, TemplateCodeInfo}; use compiler::compiler_interface::Circuit; use compiler::intermediate_representation::{Instruction, InstructionList, InstructionPointer, new_id}; - - -use std::cell::RefCell; - -use compiler::intermediate_representation::ir_interface::{ - Allocate, AssertBucket, BranchBucket, CallBucket, ComputeBucket, ConstraintBucket, - CreateCmpBucket, LoadBucket, LocationRule, LogBucket, LoopBucket, NopBucket, ReturnBucket, - StoreBucket, BlockBucket, ValueBucket, AddressType, ReturnType, FinalData, LogBucketArg, -}; - +use compiler::intermediate_representation::ir_interface::*; use crate::passes::{ conditional_flattening::ConditionalFlattening, deterministic_subcomponent_invocation::DeterministicSubCmpInvokePass, - loop_unroll::LoopUnrollPass, - mapped_to_indexed::MappedToIndexedPass, - simplification::SimplificationPass, - unknown_index_sanitization::UnknownIndexSanitizationPass, + loop_unroll::LoopUnrollPass, mapped_to_indexed::MappedToIndexedPass, + simplification::SimplificationPass, unknown_index_sanitization::UnknownIndexSanitizationPass, }; use crate::passes::checks::assert_unique_ids_in_circuit; @@ -148,7 +137,8 @@ pub trait CircuitTransformationPass { parse_as: bucket.parse_as, op_aux_no: bucket.op_aux_no, value: bucket.value, - }.allocate() + } + .allocate() } fn transform_address_type(&self, address: &AddressType) -> AddressType { @@ -367,15 +357,13 @@ pub trait CircuitTransformationPass { line: bucket.line, message_id: bucket.message_id, body: self.transform_instructions(&bucket.body), - n_iters: bucket.n_iters + n_iters: bucket.n_iters, } .allocate() } fn transform_nop_bucket(&self, _bucket: &NopBucket) -> InstructionPointer { - NopBucket { - id: new_id() - }.allocate() + NopBucket { id: new_id() }.allocate() } pre_hook!(pre_hook_circuit, Circuit); diff --git a/circuit_passes/src/passes/simplification.rs b/circuit_passes/src/passes/simplification.rs index 5f5f4ecf2..0f30d250b 100644 --- a/circuit_passes/src/passes/simplification.rs +++ b/circuit_passes/src/passes/simplification.rs @@ -1,17 +1,10 @@ use std::cell::RefCell; use std::collections::BTreeMap; - use compiler::circuit_design::template::TemplateCode; use compiler::compiler_interface::Circuit; use compiler::intermediate_representation::{InstructionPointer, new_id}; -use compiler::intermediate_representation::ir_interface::{ - Allocate, AssertBucket, BlockBucket, BranchBucket, CallBucket, ComputeBucket, ConstraintBucket, - CreateCmpBucket, LoadBucket, LocationRule, LogBucket, LoopBucket, NopBucket, ReturnBucket, - StoreBucket, ValueBucket, -}; - +use compiler::intermediate_representation::ir_interface::*; use crate::bucket_interpreter::env::Env; -use crate::bucket_interpreter::BucketInterpreter; use crate::bucket_interpreter::observer::InterpreterObserver; use crate::bucket_interpreter::value::Value; use crate::passes::CircuitTransformationPass; @@ -21,7 +14,7 @@ pub struct SimplificationPass { // Wrapped in a RefCell because the reference to the static analysis is immutable but we need mutability memory: RefCell, compute_replacements: RefCell>, - call_replacements: RefCell> + call_replacements: RefCell>, } impl SimplificationPass { @@ -29,7 +22,7 @@ impl SimplificationPass { SimplificationPass { memory: PassMemory::new_cell(prime, "".to_string(), Default::default()), compute_replacements: Default::default(), - call_replacements: Default::default() + call_replacements: Default::default(), } } } @@ -76,7 +69,9 @@ impl InterpreterObserver for SimplificationPass { true } - fn on_block_bucket(&self, _bucket: &BlockBucket, _env: &Env) -> bool { true } + fn on_block_bucket(&self, _bucket: &BlockBucket, _env: &Env) -> bool { + true + } fn on_nop_bucket(&self, _bucket: &NopBucket, _env: &Env) -> bool { true @@ -91,7 +86,8 @@ impl InterpreterObserver for SimplificationPass { let mem = self.memory.borrow(); let interpreter = mem.build_interpreter(self); let (eval, _) = interpreter.execute_call_bucket(bucket, env, false); - if let Some(eval) = eval { // Call buckets may not return a value directly + if let Some(eval) = eval { + // Call buckets may not return a value directly if !eval.is_unknown() { self.call_replacements.borrow_mut().insert(bucket.clone(), eval); return false; @@ -139,7 +135,8 @@ impl CircuitTransformationPass for SimplificationPass { op: bucket.op, op_aux_no: bucket.op_aux_no, stack: self.transform_instructions(&bucket.stack), - }.allocate() + } + .allocate() } fn transform_call_bucket(&self, bucket: &CallBucket) -> InstructionPointer { @@ -157,7 +154,8 @@ impl CircuitTransformationPass for SimplificationPass { arguments: self.transform_instructions(&bucket.arguments), arena_size: bucket.arena_size, return_info: self.transform_return_type(&bucket.return_info), - }.allocate() + } + .allocate() } fn pre_hook_circuit(&self, circuit: &Circuit) { diff --git a/circuit_passes/src/passes/unknown_index_sanitization.rs b/circuit_passes/src/passes/unknown_index_sanitization.rs index d4f8e6e88..31eb8a021 100644 --- a/circuit_passes/src/passes/unknown_index_sanitization.rs +++ b/circuit_passes/src/passes/unknown_index_sanitization.rs @@ -1,43 +1,29 @@ -use std::borrow::Borrow; use std::cell::RefCell; -use std::collections::{BTreeMap, HashMap}; - +use std::collections::BTreeMap; +use std::ops::Range; use compiler::circuit_design::template::TemplateCode; use compiler::compiler_interface::Circuit; -use compiler::intermediate_representation::{Instruction, InstructionPointer, new_id, BucketId}; -use compiler::intermediate_representation::ir_interface::{AddressType, Allocate, AssertBucket, BlockBucket, BranchBucket, CallBucket, ComputeBucket, ConstraintBucket, CreateCmpBucket, LoadBucket, LocationRule, LogBucket, LoopBucket, NopBucket, ReturnBucket, StoreBucket, ValueBucket, OperatorType, ValueType, ReturnType}; +use compiler::intermediate_representation::{Instruction, InstructionPointer, new_id}; +use compiler::intermediate_representation::ir_interface::*; use compiler::num_bigint::BigInt; -use compiler::num_traits::{int, Zero}; -use std::ops::Range; +use code_producers::llvm_elements::array_switch::{get_array_load_symbol, get_array_store_symbol}; use program_structure::constants::UsefulConstants; -use code_producers::llvm_elements::array_switch::{load_array_switch, get_array_load_symbol, get_array_store_symbol}; - use crate::bucket_interpreter::env::Env; -use crate::bucket_interpreter::{BucketInterpreter, value, R}; +use crate::bucket_interpreter::R; use crate::bucket_interpreter::observer::InterpreterObserver; use crate::bucket_interpreter::operations::compute_operation; -use crate::bucket_interpreter::value::{mod_value, resolve_operation, Value, Value::KnownU32, Value::KnownBigInt}; +use crate::bucket_interpreter::value::Value::{KnownU32, KnownBigInt}; use crate::passes::CircuitTransformationPass; use crate::passes::memory::PassMemory; - struct ZeroingInterpreter<'a> { - prime: &'a String, pub constant_fields: &'a Vec, - p: BigInt + p: BigInt, } impl<'a> ZeroingInterpreter<'a> { - - pub fn init( - prime: &'a String, - constant_fields: &'a Vec, - ) -> Self { - ZeroingInterpreter { - prime, - constant_fields, - p: UsefulConstants::new(prime).get_p().clone() - } + pub fn init(prime: &'a String, constant_fields: &'a Vec) -> Self { + ZeroingInterpreter { constant_fields, p: UsefulConstants::new(prime).get_p().clone() } } pub fn execute_value_bucket<'env>(&self, bucket: &ValueBucket, env: Env<'env>) -> R<'env> { @@ -52,15 +38,19 @@ impl<'a> ZeroingInterpreter<'a> { } ValueType::U32 => KnownU32(bucket.value), }), - env + env, ) } - pub fn execute_load_bucket<'env>(&self, bucket: &'env LoadBucket, env: Env<'env>) -> R<'env> { + pub fn execute_load_bucket<'env>(&self, _bucket: &'env LoadBucket, env: Env<'env>) -> R<'env> { (Some(KnownU32(0)), env) } - pub fn execute_compute_bucket<'env>(&self, bucket: &'env ComputeBucket, env: Env<'env>) -> R<'env> { + pub fn execute_compute_bucket<'env>( + &self, + bucket: &'env ComputeBucket, + env: Env<'env>, + ) -> R<'env> { let mut stack = vec![]; let mut env = env; for i in &bucket.stack { @@ -77,7 +67,11 @@ impl<'a> ZeroingInterpreter<'a> { (computed_value, env) } - pub fn execute_instruction<'env>(&self, inst: &'env InstructionPointer, env: Env<'env>) -> R<'env> { + pub fn execute_instruction<'env>( + &self, + inst: &'env InstructionPointer, + env: Env<'env>, + ) -> R<'env> { match inst.as_ref() { Instruction::Value(b) => self.execute_value_bucket(b, env), Instruction::Load(b) => self.execute_load_bucket(b, env), @@ -94,7 +88,6 @@ pub struct UnknownIndexSanitizationPass { store_replacements: RefCell>>, } - /** * The goal of this pass is to */ @@ -107,7 +100,12 @@ impl UnknownIndexSanitizationPass { } } - fn find_bounds(&self, address: &AddressType, location: &LocationRule, env: &Env) -> Range { + fn find_bounds( + &self, + address: &AddressType, + location: &LocationRule, + env: &Env, + ) -> Range { let mem = self.memory.borrow(); let interpreter = ZeroingInterpreter::init(&mem.prime, &mem.constant_fields); let current_scope = &mem.current_scope; @@ -115,7 +113,7 @@ impl UnknownIndexSanitizationPass { let mapping = match address { AddressType::Variable => &mem.variables_index_mapping[current_scope], AddressType::Signal => &mem.signal_index_mapping[current_scope], - AddressType::SubcmpSignal { cmp_address, .. } => &mem.component_addr_index_mapping[current_scope], + AddressType::SubcmpSignal { .. } => &mem.component_addr_index_mapping[current_scope], }; /* @@ -124,7 +122,7 @@ impl UnknownIndexSanitizationPass { * So, if we set the unknown value to 0, we will compute the base offset, * which will let us look up the range of the underlying array. * - * The expression above is for 1-D arrays, multidimensional arrays follow + * The expression above is for 1-D arrays, multidimensional arrays follow * a similar pattern that is also handled here. */ match location { @@ -137,20 +135,25 @@ impl UnknownIndexSanitizationPass { }; mapping[&offset].clone() - }, + } LocationRule::Mapped { .. } => unreachable!(), } } - fn is_location_unknown(&self, address: &AddressType, location: &LocationRule, env: &Env) -> bool { + fn is_location_unknown( + &self, + _address: &AddressType, + location: &LocationRule, + env: &Env, + ) -> bool { let mem = self.memory.borrow(); let interpreter = mem.build_interpreter(self); let resolved_addr = match location { LocationRule::Indexed { location, .. } => { - let (r, acc_env) = interpreter.execute_instruction(location, env.clone(), false); + let (r, _) = interpreter.execute_instruction(location, env.clone(), false); r.expect("location must produce a value!") - }, + } LocationRule::Mapped { .. } => unreachable!(), }; @@ -158,7 +161,6 @@ impl UnknownIndexSanitizationPass { } } - /** * The goal is to replace: * - loads with a function call that returns the loaded value @@ -247,7 +249,6 @@ impl InterpreterObserver for UnknownIndexSanitizationPass { } impl CircuitTransformationPass for UnknownIndexSanitizationPass { - fn transform_load_bucket(&self, bucket: &LoadBucket) -> InstructionPointer { let bounded_fn_symbol = match self.load_replacements.borrow().get(bucket) { Some(index_range) => Some(get_array_load_symbol(index_range)), diff --git a/code_producers/src/llvm_elements/array_switch.rs b/code_producers/src/llvm_elements/array_switch.rs index a76e3deb2..7919b6734 100644 --- a/code_producers/src/llvm_elements/array_switch.rs +++ b/code_producers/src/llvm_elements/array_switch.rs @@ -1,31 +1,22 @@ +use std::ops::Range; use inkwell::types::PointerType; - use crate::llvm_elements::LLVMIRProducer; -use std::ops::Range; - use super::types::bigint_type; mod array_switch { - use std::borrow::Borrow; use std::convert::TryInto; - use std::fmt::format; use std::ops::Range; - use inkwell::values::AnyValue; - use crate::llvm_elements::functions::{create_bb, create_function}; use crate::llvm_elements::instructions::{ - create_br, create_call, create_conditional_branch, create_eq, create_return_void, - create_store, create_gep, create_load, create_return, create_switch, - }; - use crate::llvm_elements::stdlib::{ - ASSERT_FN_NAME, CONSTRAINT_VALUE_FN_NAME, CONSTRAINT_VALUES_FN_NAME, + create_call, create_return_void, create_store, create_gep, create_load, create_return, + create_switch, }; + use crate::llvm_elements::stdlib::ASSERT_FN_NAME; use crate::llvm_elements::LLVMIRProducer; use crate::llvm_elements::types::{bigint_type, bool_type, i32_type, void_type}; use crate::llvm_elements::values::zero; - pub fn get_load_symbol(index_range: &Range) -> String { format!("__array_load__{}_to_{}", index_range.start, index_range.end) } @@ -40,12 +31,16 @@ mod array_switch { let bool_ty = bool_type(producer); let bigint_ty = bigint_type(producer); let i32_ty = i32_type(producer); - let args = &[ - bigint_ty.array_type(0).ptr_type(Default::default()).into(), - i32_ty.into(), - ]; - - let func = create_function(producer, &None, 0, "", &get_load_symbol(index_range), bigint_ty.fn_type(args, false)); + let args = &[bigint_ty.array_type(0).ptr_type(Default::default()).into(), i32_ty.into()]; + + let func = create_function( + producer, + &None, + 0, + "", + &get_load_symbol(index_range), + bigint_ty.fn_type(args, false), + ); let main = create_bb(producer, func, "main"); let arr = func.get_nth_param(0).unwrap().into_pointer_value(); @@ -73,10 +68,12 @@ mod array_switch { producer.set_current_bb(main); create_switch(producer, arr_idx, else_bb, &cases); - } - pub fn create_array_store_fn<'a>(producer: &dyn LLVMIRProducer<'a>, index_range: &Range) { + pub fn create_array_store_fn<'a>( + producer: &dyn LLVMIRProducer<'a>, + index_range: &Range, + ) { // args: array, index, value // return: void let bool_ty = bool_type(producer); @@ -88,9 +85,14 @@ mod array_switch { i32_ty.into(), bigint_ty.into(), ]; - let void_ty = void_type(producer); - - let func = create_function(producer, &None, 0, "", &get_store_symbol(index_range), void_ty.fn_type(args, false)); + let func = create_function( + producer, + &None, + 0, + "", + &get_store_symbol(index_range), + void_ty.fn_type(args, false), + ); let main = create_bb(producer, func, "main"); let arr = func.get_nth_param(0).unwrap().into_pointer_value(); @@ -120,8 +122,6 @@ mod array_switch { create_switch(producer, arr_idx, else_bb, &cases); } - - } pub fn array_ptr_ty<'a>(producer: &dyn LLVMIRProducer<'a>) -> PointerType<'a> { @@ -140,4 +140,4 @@ pub fn get_array_load_symbol(index_range: &Range) -> String { pub fn get_array_store_symbol(index_range: &Range) -> String { array_switch::get_store_symbol(index_range) -} \ No newline at end of file +} diff --git a/code_producers/src/llvm_elements/functions.rs b/code_producers/src/llvm_elements/functions.rs index 1d353e8ee..67ebbb2ce 100644 --- a/code_producers/src/llvm_elements/functions.rs +++ b/code_producers/src/llvm_elements/functions.rs @@ -131,10 +131,7 @@ impl<'a> BodyCtx<'a> for FunctionCtx<'a> { create_gep(producer, self.arena, &[index]) } - fn get_variable_array( - &self, - producer: &dyn LLVMIRProducer<'a>, - ) -> AnyValueEnum<'a> { + fn get_variable_array(&self, _producer: &dyn LLVMIRProducer<'a>) -> AnyValueEnum<'a> { self.arena.into() } } diff --git a/code_producers/src/llvm_elements/template.rs b/code_producers/src/llvm_elements/template.rs index 0f17f2be4..10b3946ba 100644 --- a/code_producers/src/llvm_elements/template.rs +++ b/code_producers/src/llvm_elements/template.rs @@ -2,7 +2,7 @@ use inkwell::basic_block::BasicBlock; use inkwell::builder::Builder; use inkwell::context::ContextRef; use inkwell::types::{AnyType, BasicType, PointerType}; -use inkwell::values::{AnyValue, AnyValueEnum, ArrayValue, FunctionValue, IntValue, PointerValue}; +use inkwell::values::{AnyValueEnum, ArrayValue, FunctionValue, IntValue, PointerValue}; use crate::llvm_elements::{BodyCtx, LLVM, LLVMIRProducer}; use crate::llvm_elements::instructions::{create_alloca, create_gep, create_load}; @@ -169,7 +169,7 @@ impl<'a> TemplateCtx<'a> { /// Returns a pointer to the signal array pub fn get_signal_array( &self, - producer: &dyn LLVMIRProducer<'a>, + _producer: &dyn LLVMIRProducer<'a>, ) -> AnyValueEnum<'a> { let signals = self.current_function.get_nth_param(self.signals_arg_offset as u32).unwrap(); signals.into_pointer_value().into() @@ -188,7 +188,7 @@ impl<'a> BodyCtx<'a> for TemplateCtx<'a> { fn get_variable_array( &self, - producer: &dyn LLVMIRProducer<'a>, + _producer: &dyn LLVMIRProducer<'a>, ) -> AnyValueEnum<'a> { self.stack.into() } diff --git a/compiler/src/circuit_design/build.rs b/compiler/src/circuit_design/build.rs index 98f7ca34a..9175119c8 100644 --- a/compiler/src/circuit_design/build.rs +++ b/compiler/src/circuit_design/build.rs @@ -1,14 +1,14 @@ +use std::collections::{BTreeMap, HashMap}; use crate::circuit_design::circuit::{Circuit, CompilationFlags}; use crate::circuit_design::function::FunctionCodeInfo; use crate::circuit_design::template::TemplateCodeInfo; use crate::hir::very_concrete_program::*; -use crate::intermediate_representation::{Instruction, translate}; -use crate::intermediate_representation::translate::{CodeInfo, FieldTracker, TemplateDB, ParallelClusters, SSACollector, SSA}; +use crate::intermediate_representation::translate; +use crate::intermediate_representation::translate::{CodeInfo, FieldTracker, TemplateDB, ParallelClusters, SSACollector}; use code_producers::c_elements::*; use code_producers::wasm_elements::*; -use program_structure::file_definition::FileLibrary; -use std::collections::{BTreeMap, HashMap}; use code_producers::llvm_elements::LLVMCircuitData; +use program_structure::file_definition::FileLibrary; #[cfg(debug_assertions)] fn matching_lengths_and_offsets(list: &InputOutputList) { diff --git a/compiler/src/intermediate_representation/block_bucket.rs b/compiler/src/intermediate_representation/block_bucket.rs index 22c8448ce..0069982c8 100644 --- a/compiler/src/intermediate_representation/block_bucket.rs +++ b/compiler/src/intermediate_representation/block_bucket.rs @@ -1,4 +1,3 @@ -use pretty::{Doc, RcDoc}; use code_producers::llvm_elements::{LLVMInstruction, LLVMIRProducer}; use crate::intermediate_representation::{BucketId, Instruction, InstructionList, InstructionPointer, new_id, SExp, ToSExp, UpdateId}; use crate::intermediate_representation::ir_interface::{Allocate, IntoInstruction, ObtainMeta}; diff --git a/compiler/src/intermediate_representation/call_bucket.rs b/compiler/src/intermediate_representation/call_bucket.rs index b32316c56..ce984a107 100644 --- a/compiler/src/intermediate_representation/call_bucket.rs +++ b/compiler/src/intermediate_representation/call_bucket.rs @@ -1,4 +1,3 @@ -use std::path::is_separator; use either::Either; use super::ir_interface::*; use crate::translating_traits::*; diff --git a/compiler/src/intermediate_representation/translate.rs b/compiler/src/intermediate_representation/translate.rs index df51c1111..2d10881d3 100644 --- a/compiler/src/intermediate_representation/translate.rs +++ b/compiler/src/intermediate_representation/translate.rs @@ -98,12 +98,6 @@ struct Counter { } impl Counter { - pub fn init() -> Self { - Counter { - value: 0 - } - } - pub fn get_and_inc(&mut self) -> usize { let v = self.value; self.value += 1; @@ -1107,7 +1101,7 @@ struct ProcessedSymbol { signal: Option, signal_type: Option, before_signal: Vec, - meta: Meta + _meta: Meta } impl ProcessedSymbol { @@ -1186,7 +1180,7 @@ impl ProcessedSymbol { before_signal: bf_index, signal: signal_location, signal_type, - meta + _meta: meta } } @@ -1417,7 +1411,7 @@ fn indexing_instructions_filter( index_stack } -fn op_to_opcode(op: OperatorType) -> ExpressionInfixOpcode { +fn _op_to_opcode(op: OperatorType) -> ExpressionInfixOpcode { match op { OperatorType::Mul => ExpressionInfixOpcode::Mul, OperatorType::Div => ExpressionInfixOpcode::Div, diff --git a/parser/Cargo.toml b/parser/Cargo.toml index 03f7837a2..83a5a327e 100644 --- a/parser/Cargo.toml +++ b/parser/Cargo.toml @@ -7,13 +7,13 @@ build = "build.rs" [build-dependencies] rustc-hex = "2.0.1" -lalrpop = { version = "0.18.1", features = ["lexer"] } +lalrpop = { version = "0.20.0", features = ["lexer"] } num-bigint-dig = "0.6.0" num-traits = "0.2.6" [dependencies] program_structure = {path = "../program_structure"} -lalrpop-util = "0.18.1" +lalrpop-util = "0.20.0" regex = "1.1.2" rustc-hex = "2.0.1" num-bigint-dig = "0.6.0" diff --git a/parser/src/lib.rs b/parser/src/lib.rs index b77e7bb20..1a1b1c547 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -15,10 +15,10 @@ mod syntax_sugar_remover; use include_logic::{FileStack, IncludesGraph}; use program_structure::error_code::ReportCode; use program_structure::error_definition::{Report, ReportCollection}; -use program_structure::file_definition::{FileLibrary}; +use program_structure::file_definition::FileLibrary; use program_structure::program_archive::ProgramArchive; use std::path::{PathBuf, Path}; -use syntax_sugar_remover::{apply_syntactic_sugar}; +use syntax_sugar_remover::apply_syntactic_sugar; use std::str::FromStr; diff --git a/parser/src/syntax_sugar_remover.rs b/parser/src/syntax_sugar_remover.rs index 713c05e66..7cc8dbe5b 100644 --- a/parser/src/syntax_sugar_remover.rs +++ b/parser/src/syntax_sugar_remover.rs @@ -1,11 +1,11 @@ use program_structure::ast::*; use program_structure::statement_builders::{build_block, build_substitution}; -use program_structure::error_definition::{Report}; +use program_structure::error_definition::Report; use program_structure::expression_builders::{build_call, build_tuple, build_parallel_op}; use program_structure::file_definition::FileLibrary; use program_structure::program_archive::ProgramArchive; use program_structure::statement_builders::{build_declaration, build_log_call, build_assert, build_return, build_constraint_equality, build_initialization_block}; -use program_structure::template_data::{TemplateData}; +use program_structure::template_data::TemplateData; use std::collections::HashMap; use num_bigint::BigInt; diff --git a/summary/Cargo.toml b/summary/Cargo.toml index debbac595..17424330d 100644 --- a/summary/Cargo.toml +++ b/summary/Cargo.toml @@ -5,6 +5,9 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[build-dependencies] +serde = { version = "1.0", features = ["derive"] } + [dependencies] serde_json = "1.0" serde = "1.0" diff --git a/summary/src/lib.rs b/summary/src/lib.rs index 15104e8bf..74d39de0c 100644 --- a/summary/src/lib.rs +++ b/summary/src/lib.rs @@ -1,18 +1,17 @@ use std::collections::HashMap; use std::fs::File; -use compiler::hir::very_concrete_program::{Component, TemplateInstance, VCP}; -use compiler::intermediate_representation::translate::{initialize_signals, SignalInfo, State, TemplateDB}; -use program_structure::ast::SignalType; +use compiler::hir::very_concrete_program::{TemplateInstance, VCP}; +use compiler::intermediate_representation::translate::{initialize_signals, SignalInfo, State}; use code_producers::llvm_elements::{build_fn_name, run_fn_name}; -use serde::Serialize; use constant_tracking::ConstantTracker; +use program_structure::ast::SignalType; use program_structure::file_definition::FileLibrary; - +use serde::Serialize; #[derive(Serialize)] struct Meta { is_ir_ssa: bool, - prime: String + prime: String, } #[derive(Serialize)] @@ -20,13 +19,13 @@ struct SignalSummary { name: String, visibility: String, idx: usize, - public: bool + public: bool, } #[derive(Serialize)] struct SubcmpSummary { name: String, - idx: usize + idx: usize, } #[derive(Serialize)] @@ -54,12 +53,12 @@ pub struct SummaryRoot { framework: Option, meta: Meta, components: Vec, - functions: Vec + functions: Vec, } fn index_names(lengths: &[usize]) -> Vec { if lengths.is_empty() { - return vec!["".to_string()] + return vec!["".to_string()]; } let hd = lengths[0]; let tl = &lengths[1..lengths.len()]; @@ -81,11 +80,12 @@ fn unroll_signal(name: &String, info: &SignalInfo, idx: usize) -> Vec "output", SignalType::Input => "input", - SignalType::Intermediate => "intermediate" - }.to_string(), + SignalType::Intermediate => "intermediate", + } + .to_string(), public: false, - idx - }] + idx, + }]; } let mut signals = vec![]; @@ -95,10 +95,11 @@ fn unroll_signal(name: &String, info: &SignalInfo, idx: usize) -> Vec "output", SignalType::Input => "input", - SignalType::Intermediate => "intermediate" - }.to_string(), + SignalType::Intermediate => "intermediate", + } + .to_string(), idx: idx + offset, - public: false + public: false, }) } @@ -107,38 +108,19 @@ fn unroll_signal(name: &String, info: &SignalInfo, idx: usize) -> Vec Vec { if lengths.is_empty() { - return vec![SubcmpSummary { - name: name.to_string(), - idx - }] + return vec![SubcmpSummary { name: name.to_string(), idx }]; } let mut subcmps = vec![]; - for (offset, indices) in index_names(lengths).iter().enumerate() { - subcmps.push(SubcmpSummary { - name: format!("{name}{indices}"), - idx: idx + offset - }) + for (offset, indices) in index_names(lengths).iter().enumerate() { + subcmps.push(SubcmpSummary { name: format!("{name}{indices}"), idx: idx + offset }) } subcmps } impl SummaryRoot { - fn prepare_template_instances(templates: &[TemplateInstance]) -> HashMap { - templates.iter().map(|i| (i.template_id, i)).collect() - } - - fn prepare_signals(template: &TemplateInstance) -> HashMap { - let mut signal_info = HashMap::new(); - for signal in template.signals.clone() { - let info = SignalInfo{ signal_type: signal.xtype, lengths: signal.lengths}; - signal_info.insert(signal.name, info); - } - signal_info - } - fn create_state(template: &TemplateInstance) -> State { State::new( template.template_id, @@ -187,7 +169,7 @@ impl SummaryRoot { subcmps, signals, logic_fn_name: run_fn_name(template.template_header.clone()), - constructor_fn_name: build_fn_name(template.template_header.clone()) + constructor_fn_name: build_fn_name(template.template_header.clone()), } } @@ -213,4 +195,4 @@ impl SummaryRoot { let writer = File::create(summary_file).unwrap(); serde_json::to_writer(&writer, &self) } -} \ No newline at end of file +} From f44eea412320b06691fde14e923fb9db67a6a8e0 Mon Sep 17 00:00:00 2001 From: Timothy Hoffman <4001421+tim-hoffman@users.noreply.github.com> Date: Thu, 10 Aug 2023 10:05:02 -0500 Subject: [PATCH 03/12] add debug info to the unique id assertions (#41) --- circuit_passes/src/passes/checks.rs | 93 ++++++++++++++++------------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/circuit_passes/src/passes/checks.rs b/circuit_passes/src/passes/checks.rs index ccd0ba581..c6c084716 100644 --- a/circuit_passes/src/passes/checks.rs +++ b/circuit_passes/src/passes/checks.rs @@ -1,142 +1,149 @@ -use std::collections::HashSet; +use std::collections::HashMap; use compiler::circuit_design::function::FunctionCode; use compiler::circuit_design::template::TemplateCode; use compiler::compiler_interface::Circuit; -use compiler::intermediate_representation::{BucketId, Instruction, InstructionList, InstructionPointer}; -use compiler::intermediate_representation::ir_interface::{AddressType, LocationRule, LogBucketArg, ReturnType}; +use compiler::intermediate_representation::{ + BucketId, Instruction, InstructionList, InstructionPointer, +}; +use compiler::intermediate_representation::ir_interface::{ + AddressType, LocationRule, LogBucketArg, ReturnType, +}; -type Ids<'a> = &'a mut HashSet; +type Ids<'a, 'b> = &'a mut HashMap; -fn assert_unique_ids_in_location_rule(location: &LocationRule, ids: Ids) { +fn assert_unique_ids_in_location_rule<'a, 'b: 'a>(location: &'b LocationRule, ids: Ids<'a, 'b>) { match location { LocationRule::Indexed { location, .. } => assert_unique_ids_in_instruction(location, ids), - LocationRule::Mapped { indexes, .. } => assert_unique_ids_in_instruction_list(indexes, ids) + LocationRule::Mapped { indexes, .. } => assert_unique_ids_in_instruction_list(indexes, ids), } } -fn assert_unique_ids_in_address_type(address: &AddressType, ids: Ids) { +fn assert_unique_ids_in_address_type<'a, 'b: 'a>(address: &'b AddressType, ids: Ids<'a, 'b>) { match address { AddressType::Variable => {} AddressType::Signal => {} - AddressType::SubcmpSignal { cmp_address, .. } => assert_unique_ids_in_instruction(cmp_address, ids) + AddressType::SubcmpSignal { cmp_address, .. } => { + assert_unique_ids_in_instruction(cmp_address, ids) + } } } -fn assert_unique_ids_in_return_type(return_type: &ReturnType, ids: Ids) { +fn assert_unique_ids_in_return_type<'a, 'b: 'a>(return_type: &'b ReturnType, ids: Ids<'a, 'b>) { if let ReturnType::Final(data) = return_type { assert_unique_ids_in_location_rule(&data.dest, ids); assert_unique_ids_in_address_type(&data.dest_address_type, ids); } } -fn assert_unique_ids_in_log_args(log_args: &LogBucketArg, ids: Ids) { +fn assert_unique_ids_in_log_args<'a, 'b: 'a>(log_args: &'b LogBucketArg, ids: Ids<'a, 'b>) { if let LogBucketArg::LogExp(e) = log_args { assert_unique_ids_in_instruction(e, ids); } } -fn assert_unique_ids_in_instruction(inst: &InstructionPointer, ids: Ids) { +macro_rules! check_and_handle_ids { + ($inst: expr, $bucket: expr, $ids: expr) => {{ + assert!( + !$ids.contains_key(&$bucket.id), + "Same ID for [{0:p}]{0:?} and [{1:p}]{1:?}", + *$inst, + **$ids.get(&$bucket.id).unwrap() + ); + $ids.insert($bucket.id, $inst); + }}; +} + +fn assert_unique_ids_in_instruction<'a, 'b: 'a>(inst: &'b InstructionPointer, ids: Ids<'a, 'b>) { match inst.as_ref() { Instruction::Value(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); } Instruction::Load(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_location_rule(&b.src, ids); assert_unique_ids_in_address_type(&b.address_type, ids); } Instruction::Store(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_address_type(&b.dest_address_type, ids); assert_unique_ids_in_location_rule(&b.dest, ids); assert_unique_ids_in_instruction(&b.src, ids); } Instruction::Compute(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_instruction_list(&b.stack, ids); } Instruction::Call(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_return_type(&b.return_info, ids) } Instruction::Branch(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_instruction(&b.cond, ids); assert_unique_ids_in_instruction_list(&b.if_branch, ids); assert_unique_ids_in_instruction_list(&b.else_branch, ids); } Instruction::Return(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_instruction(&b.value, ids); } Instruction::Assert(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_instruction(&b.evaluate, ids); } Instruction::Log(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); for arg in &b.argsprint { assert_unique_ids_in_log_args(arg, ids); } } Instruction::Loop(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_instruction(&b.continue_condition, ids); assert_unique_ids_in_instruction_list(&b.body, ids); } Instruction::CreateCmp(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_instruction(&b.sub_cmp_id, ids); } Instruction::Constraint(b) => { assert_unique_ids_in_instruction(b.unwrap(), ids); } Instruction::Block(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); assert_unique_ids_in_instruction_list(&b.body, ids); } Instruction::Nop(b) => { - assert!(!ids.contains(&b.id)); - ids.insert(b.id); + check_and_handle_ids!(inst, b, ids); } } } -fn assert_unique_ids_in_instruction_list(instructions: &InstructionList, ids: Ids) { +fn assert_unique_ids_in_instruction_list<'a, 'b: 'a>( + instructions: &'b InstructionList, + ids: Ids<'a, 'b>, +) { for inst in instructions { assert_unique_ids_in_instruction(inst, ids); } } -fn assert_unique_ids_in_template(template: &TemplateCode, ids: Ids) { +fn assert_unique_ids_in_template<'a, 'b: 'a>(template: &'b TemplateCode, ids: Ids<'a, 'b>) { assert_unique_ids_in_instruction_list(&template.body, ids); } -fn assert_unique_ids_in_function(function: &FunctionCode, ids: Ids) { +fn assert_unique_ids_in_function<'a, 'b: 'a>(function: &'b FunctionCode, ids: Ids<'a, 'b>) { assert_unique_ids_in_instruction_list(&function.body, ids); - } /// Ensures that the ids of the buckets in a circuit are all unique /// Panics if not as duplicate ids are usually indicative of a bug in a pass pub fn assert_unique_ids_in_circuit(circuit: &Circuit) { - let mut visited: HashSet = Default::default(); + let mut visited: HashMap = HashMap::new(); for template in &circuit.templates { assert_unique_ids_in_template(template, &mut visited); } for function in &circuit.functions { assert_unique_ids_in_function(function, &mut visited); } -} \ No newline at end of file +} From e43791210bf7000e76b0cbbe9defe0381923225f Mon Sep 17 00:00:00 2001 From: Timothy Hoffman <4001421+tim-hoffman@users.noreply.github.com> Date: Thu, 10 Aug 2023 15:05:00 -0500 Subject: [PATCH 04/12] [VAN-521] implement a case of mapped to indexed location conversion (#40) --- circom/tests/subcmps/conv_map2idx_A.circom | 20 +++++++++++ circom/tests/subcmps/conv_map2idx_B.circom | 23 +++++++++++++ circuit_passes/src/bucket_interpreter/mod.rs | 33 +++++++++---------- .../src/passes/mapped_to_indexed.rs | 33 ++++++++++++------- 4 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 circom/tests/subcmps/conv_map2idx_A.circom create mode 100644 circom/tests/subcmps/conv_map2idx_B.circom diff --git a/circom/tests/subcmps/conv_map2idx_A.circom b/circom/tests/subcmps/conv_map2idx_A.circom new file mode 100644 index 000000000..3c4c0afc4 --- /dev/null +++ b/circom/tests/subcmps/conv_map2idx_A.circom @@ -0,0 +1,20 @@ +pragma circom 2.0.3; + +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s + +template GetWeight(A) { + signal input inp; +} + +template ComputeValue() { + component getWeights[2]; + + getWeights[0] = GetWeight(0); + getWeights[0].inp <-- 888; + + getWeights[1] = GetWeight(1); + getWeights[1].inp <-- 999; +} + +component main = ComputeValue(); diff --git a/circom/tests/subcmps/conv_map2idx_B.circom b/circom/tests/subcmps/conv_map2idx_B.circom new file mode 100644 index 000000000..76f067882 --- /dev/null +++ b/circom/tests/subcmps/conv_map2idx_B.circom @@ -0,0 +1,23 @@ +pragma circom 2.0.3; + +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s + +template GetWeight(A, B) { + signal output x; //signal index 0 + signal output y; //signal index 1 + signal output out; //signal index 2 + out <-- A; +} + +template ComputeValue() { + component ws[2]; + ws[0] = GetWeight(999, 0); + ws[1] = GetWeight(888, 1); + + signal ret[2]; + ret[0] <== ws[0].out; + ret[1] <== ws[1].out; +} + +component main = ComputeValue(); diff --git a/circuit_passes/src/bucket_interpreter/mod.rs b/circuit_passes/src/bucket_interpreter/mod.rs index 3c82cc7fe..a4df040e0 100644 --- a/circuit_passes/src/bucket_interpreter/mod.rs +++ b/circuit_passes/src/bucket_interpreter/mod.rs @@ -243,22 +243,22 @@ impl<'a> BucketInterpreter<'a> { (idx.expect("Indexed location must produce a value!").get_u32(), env) }, LocationRule::Mapped { signal_code, indexes } => { - let mut indexes_values = vec![]; let mut acc_env = env; - for i in indexes { - let (val, new_env) = self.execute_instruction(i, acc_env, continue_observing); - indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); - acc_env = new_env; - } + let map_access = self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code].offset; if indexes.len() > 0 { - let map_access = &self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code].offset; + let mut indexes_values = vec![]; + for i in indexes { + let (val, new_env) = self.execute_instruction(i, acc_env, continue_observing); + indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); + acc_env = new_env; + } if indexes.len() == 1 { (map_access + indexes_values[0], acc_env) } else { todo!() } } else { - unreachable!() + (map_access, acc_env) } } }; @@ -316,24 +316,23 @@ impl<'a> BucketInterpreter<'a> { (idx.expect("Indexed location must produce a value!").get_u32(), env, template_header.clone()) }, LocationRule::Mapped { signal_code, indexes } => { - let mut indexes_values = vec![]; let mut acc_env = env; - for i in indexes { - let (val, new_env) = self.execute_instruction(i, acc_env, continue_observing); - indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); - acc_env = new_env; - } let name = Some(acc_env.get_subcmp_name(addr).clone()); + let map_access = self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code].offset; if indexes.len() > 0 { - //eprintln!("IO MAP crashes ({addr}): {:?}", self.io_map.contains_key(&1)); - let map_access = &self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code].offset; + let mut indexes_values = vec![]; + for i in indexes { + let (val, new_env) = self.execute_instruction(i, acc_env, continue_observing); + indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); + acc_env = new_env; + } if indexes.len() == 1 { (map_access + indexes_values[0], acc_env, name) } else { todo!() } } else { - unreachable!() + (map_access, acc_env, name) } } }; diff --git a/circuit_passes/src/passes/mapped_to_indexed.rs b/circuit_passes/src/passes/mapped_to_indexed.rs index 695c2f6d1..027ba59fa 100644 --- a/circuit_passes/src/passes/mapped_to_indexed.rs +++ b/circuit_passes/src/passes/mapped_to_indexed.rs @@ -3,6 +3,7 @@ use std::collections::BTreeMap; use compiler::circuit_design::template::TemplateCode; use compiler::compiler_interface::Circuit; use compiler::intermediate_representation::ir_interface::*; +use compiler::intermediate_representation::{InstructionPointer, UpdateId}; use crate::bucket_interpreter::env::Env; use crate::bucket_interpreter::observer::InterpreterObserver; use crate::bucket_interpreter::value::Value::KnownU32; @@ -32,26 +33,32 @@ impl MappedToIndexedPass { .expect("cmp_address instruction in SubcmpSignal must produce a value!") .get_u32(); - let name = acc_env.get_subcmp_name(resolved_addr).clone(); - let mut indexes_values = vec![]; let mut acc_env = acc_env; - for i in indexes { - let (val, new_env) = interpreter.execute_instruction(i, acc_env, false); - indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); - acc_env = new_env; - } - + let name = acc_env.get_subcmp_name(resolved_addr).clone(); + let map_access = mem.io_map[&acc_env.get_subcmp_template_id(resolved_addr)][signal_code].offset; if indexes.len() > 0 { + let mut indexes_values = vec![]; + for i in indexes { + let (val, new_env) = interpreter.execute_instruction(i, acc_env, false); + indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); + acc_env = new_env; + } if indexes.len() == 1 { - let map_access = &mem.io_map[&acc_env.get_subcmp_template_id(resolved_addr)][signal_code].offset; let value = map_access + indexes_values[0]; let mut unused = vec![]; - LocationRule::Indexed { location: KnownU32(value).to_value_bucket(&mut unused).allocate(), template_header: Some(name) } + LocationRule::Indexed { + location: KnownU32(value).to_value_bucket(&mut unused).allocate(), + template_header: Some(name), + } } else { todo!() } } else { - unreachable!() + let mut unused = vec![]; + LocationRule::Indexed { + location: KnownU32(map_access).to_value_bucket(&mut unused).allocate(), + template_header: Some(name), + } } } @@ -159,7 +166,9 @@ impl CircuitTransformationPass for MappedToIndexedPass { fn transform_location_rule(&self, location_rule: &LocationRule) -> LocationRule { // If the interpreter found a viable transformation, do that. if let Some(indexed_rule) = self.replacements.borrow().get(&location_rule) { - return indexed_rule.clone(); + let mut clone = indexed_rule.clone(); + clone.update_id(); //generate a new unique ID for the clone to avoid assertion in checks.rs + return clone; } match location_rule { LocationRule::Indexed { location, template_header } => LocationRule::Indexed { From 479715d863805b0819a00d288ce71a0fef35de1f Mon Sep 17 00:00:00 2001 From: Ian Neal Date: Wed, 16 Aug 2023 12:02:12 -0400 Subject: [PATCH 05/12] Generalize mapped offset computation, add tests (#42) --- circom/tests/subcmps/mapped3.circom | 50 +++++++++++++++++ circom/tests/subcmps/mapped4.circom | 53 +++++++++++++++++++ circuit_passes/src/bucket_interpreter/mod.rs | 21 ++++---- .../src/bucket_interpreter/operations.rs | 52 ++++++++++++++++++ .../src/passes/mapped_to_indexed.rs | 18 +++---- 5 files changed, 172 insertions(+), 22 deletions(-) create mode 100644 circom/tests/subcmps/mapped3.circom create mode 100644 circom/tests/subcmps/mapped4.circom diff --git a/circom/tests/subcmps/mapped3.circom b/circom/tests/subcmps/mapped3.circom new file mode 100644 index 000000000..61b330457 --- /dev/null +++ b/circom/tests/subcmps/mapped3.circom @@ -0,0 +1,50 @@ +pragma circom 2.0.0; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s + +template ArrayOp(q) { + signal input inp[15]; + signal output outp[15]; + + for (var i = 0; i < 15; i++) { + outp[i] <== inp[i] + q; + } +} + +//CHECK-LABEL: define void @ArrayOp_{{[0-9]+}}_build +//CHECK-SAME: ({ [0 x i256]*, i32 }* %{{.*}}) +//CHECK: alloca [30 x i256] +//CHECK: %[[DIM_REG:.*]] = getelementptr { [0 x i256]*, i32 }, { [0 x i256]*, i32 }* %0, i32 0, i32 1 +//CHECK: store i32 15, i32* %{{.*}}[[DIM_REG]] + +template Wrapper() { + signal input inp[15]; + signal output outp; + + component m[4]; + + for (var q = 0; q < 4; q++) { + // This test exhibits the behavior because the array of different subcomponents + // (differentiated by the template parameter changing) + m[q] = ArrayOp(q); + for (var i = 0; i < 15; i++) { + m[q].inp[i] <== inp[i]; + } + } + + outp <== m[2].outp[3]; +} + +component main = Wrapper(); + +//CHECK-LABEL: define void @Wrapper_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %{{.*}}) +//CHECK: %lvars = alloca [2 x i256] +//COM: offset = (1 * (3 * 7)) + (2 * (7)) + (3) + 1 (since 0 is output) = 21 + 14 + 3 + 1 = 39 +//CHECK: store{{.*}}:{{.*}}; preds = %unrolled_loop{{.*}} +//CHECK: %[[SUB_PTR:.*]] = getelementptr [4 x { [0 x i256]*, i32 }], [4 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 2, i32 0 +//CHECK: %[[SUBCMP:.*]] = load [0 x i256]*, [0 x i256]** %[[SUB_PTR]] +//CHECK: %[[VAL_PTR:.*]] = getelementptr [0 x i256], [0 x i256]* %[[SUBCMP]], i32 0, i32 3 +//CHECK: %[[VAL:.*]] = load i256, i256* %[[VAL_PTR]] +//CHECK: %[[OUTP_PTR:.*]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0 +//CHECK: store i256 %[[VAL]], i256* %[[OUTP_PTR]] diff --git a/circom/tests/subcmps/mapped4.circom b/circom/tests/subcmps/mapped4.circom new file mode 100644 index 000000000..279ca8834 --- /dev/null +++ b/circom/tests/subcmps/mapped4.circom @@ -0,0 +1,53 @@ +pragma circom 2.0.0; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s + +template MatrixOp(q) { + signal input inp[5][3]; + signal output outp[5][3]; + + for (var i = 0; i < 5; i++) { + for (var j = 0; j < 3; j++) { + outp[i][j] <== inp[i][j] + q; + } + } +} + +//CHECK-LABEL: define void @MatrixOp_{{[0-9]+}}_build +//CHECK-SAME: ({ [0 x i256]*, i32 }* %{{.*}}) +//CHECK: alloca [16 x i256] +//CHECK: %[[DIM_REG:.*]] = getelementptr { [0 x i256]*, i32 }, { [0 x i256]*, i32 }* %0, i32 0, i32 1 +//CHECK: store i32 15, i32* %{{.*}}[[DIM_REG]] + +template Wrapper() { + signal input inp[5][3]; + signal output outp; + + component m[4]; + + for (var q = 0; q < 4; q++) { + // This test exhibits the behavior because the array of different subcomponents + // (differentiated by the template parameter changing) + m[q] = MatrixOp(q); + for (var i = 0; i < 5; i++) { + for (var j = 0; j < 3; j++) { + m[q].inp[i][j] <== inp[i][j]; + } + } + } + + outp <== m[2].outp[1][2]; +} + +component main = Wrapper(); + +//CHECK-LABEL: define void @Wrapper_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %{{.*}}) +//CHECK: %lvars = alloca [3 x i256] +//CHECK: store{{.*}}:{{.*}}; preds = %unrolled_loop{{.*}} +//CHECK: %[[SUB_PTR:.*]] = getelementptr [4 x { [0 x i256]*, i32 }], [4 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 2, i32 0 +//CHECK: %[[SUBCMP:.*]] = load [0 x i256]*, [0 x i256]** %[[SUB_PTR]] +//CHECK: %[[VAL_PTR:.*]] = getelementptr [0 x i256], [0 x i256]* %[[SUBCMP]], i32 0, i32 5 +//CHECK: %[[VAL:.*]] = load i256, i256* %[[VAL_PTR]] +//CHECK: %[[OUTP_PTR:.*]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0 +//CHECK: store i256 %[[VAL]], i256* %[[OUTP_PTR]] diff --git a/circuit_passes/src/bucket_interpreter/mod.rs b/circuit_passes/src/bucket_interpreter/mod.rs index a4df040e0..cb1c7d800 100644 --- a/circuit_passes/src/bucket_interpreter/mod.rs +++ b/circuit_passes/src/bucket_interpreter/mod.rs @@ -12,6 +12,7 @@ use compiler::num_bigint::BigInt; use observer::InterpreterObserver; use program_structure::constants::UsefulConstants; use crate::bucket_interpreter::env::Env; +use crate::bucket_interpreter::operations::compute_offset; use crate::bucket_interpreter::value::{JoinSemiLattice, Value}; use crate::bucket_interpreter::value::Value::{KnownBigInt, KnownU32, Unknown}; @@ -244,7 +245,8 @@ impl<'a> BucketInterpreter<'a> { }, LocationRule::Mapped { signal_code, indexes } => { let mut acc_env = env; - let map_access = self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code].offset; + let io_def = &self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code]; + let map_access = io_def.offset; if indexes.len() > 0 { let mut indexes_values = vec![]; for i in indexes { @@ -252,11 +254,8 @@ impl<'a> BucketInterpreter<'a> { indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); acc_env = new_env; } - if indexes.len() == 1 { - (map_access + indexes_values[0], acc_env) - } else { - todo!() - } + let offset = compute_offset(&indexes_values, &io_def.lengths); + (map_access + offset, acc_env) } else { (map_access, acc_env) } @@ -318,7 +317,8 @@ impl<'a> BucketInterpreter<'a> { LocationRule::Mapped { signal_code, indexes } => { let mut acc_env = env; let name = Some(acc_env.get_subcmp_name(addr).clone()); - let map_access = self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code].offset; + let io_def = &self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code]; + let map_access = io_def.offset; if indexes.len() > 0 { let mut indexes_values = vec![]; for i in indexes { @@ -326,11 +326,8 @@ impl<'a> BucketInterpreter<'a> { indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); acc_env = new_env; } - if indexes.len() == 1 { - (map_access + indexes_values[0], acc_env, name) - } else { - todo!() - } + let offset = compute_offset(&indexes_values, &io_def.lengths); + (map_access + offset, acc_env, name) } else { (map_access, acc_env, name) } diff --git a/circuit_passes/src/bucket_interpreter/operations.rs b/circuit_passes/src/bucket_interpreter/operations.rs index e4e21ca67..9f5848823 100644 --- a/circuit_passes/src/bucket_interpreter/operations.rs +++ b/circuit_passes/src/bucket_interpreter/operations.rs @@ -40,3 +40,55 @@ pub fn compute_operation(bucket: &ComputeBucket, stack: &Vec, p: &BigInt) }); computed_value } + +pub fn compute_offset(indexes: &Vec, lengths: &Vec) -> usize { + // Lengths are in order, i.e. arr[x][y] => [x, y], same with indices + // arr[x][y] is x arrays of length y, laid out sequentially + if indexes.len() != lengths.len() { + // I did check, both "indexes" and "indices" are valid plurals + panic!("must have the same number of indexes and array lengths!"); + } + let mut total_offset = indexes.last().copied().expect("must contain some indexes!"); + let mut size_multiplier = lengths.last().copied().expect("must contain some array lengths!"); + for i in (0..lengths.len()-1).rev() { + total_offset += indexes[i] * size_multiplier; + size_multiplier *= lengths[i]; + } + total_offset +} + +#[cfg(test)] +mod test { + use super::compute_offset; + + #[test] + fn test_expected_offset() { + let offset = compute_offset(&vec![1, 1], &vec![5, 3]); + assert_eq!(4, offset); + } + + #[test] + fn test_offsets() { + let lengths = vec![5, 3, 7]; + for i in 0..lengths[0] { + for j in 0..lengths[1] { + for k in 0..lengths[2] { + let offset = compute_offset(&vec![i, j, k], &lengths); + assert_eq!((i * 21) + (j * 7) + k, offset, "i={}, j={}, k={}", i, j, k); + } + } + } + } + + #[test] + fn test_increments() { + let lengths = vec![5, 7]; + for i in 0..lengths[0] { + for j in 0..lengths[1]-1 { + let offset = compute_offset(&vec![i, j], &lengths); + let next_offset = compute_offset(&vec![i, j + 1], &lengths); + assert_eq!(offset + 1, next_offset); + } + } + } +} \ No newline at end of file diff --git a/circuit_passes/src/passes/mapped_to_indexed.rs b/circuit_passes/src/passes/mapped_to_indexed.rs index 027ba59fa..7712f2b3b 100644 --- a/circuit_passes/src/passes/mapped_to_indexed.rs +++ b/circuit_passes/src/passes/mapped_to_indexed.rs @@ -6,6 +6,7 @@ use compiler::intermediate_representation::ir_interface::*; use compiler::intermediate_representation::{InstructionPointer, UpdateId}; use crate::bucket_interpreter::env::Env; use crate::bucket_interpreter::observer::InterpreterObserver; +use crate::bucket_interpreter::operations::compute_offset; use crate::bucket_interpreter::value::Value::KnownU32; use crate::passes::CircuitTransformationPass; use crate::passes::memory::PassMemory; @@ -35,7 +36,8 @@ impl MappedToIndexedPass { let mut acc_env = acc_env; let name = acc_env.get_subcmp_name(resolved_addr).clone(); - let map_access = mem.io_map[&acc_env.get_subcmp_template_id(resolved_addr)][signal_code].offset; + let io_def = &mem.io_map[&acc_env.get_subcmp_template_id(resolved_addr)][signal_code]; + let map_access = io_def.offset; if indexes.len() > 0 { let mut indexes_values = vec![]; for i in indexes { @@ -43,15 +45,11 @@ impl MappedToIndexedPass { indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); acc_env = new_env; } - if indexes.len() == 1 { - let value = map_access + indexes_values[0]; - let mut unused = vec![]; - LocationRule::Indexed { - location: KnownU32(value).to_value_bucket(&mut unused).allocate(), - template_header: Some(name), - } - } else { - todo!() + let offset = compute_offset(&indexes_values, &io_def.lengths); + let mut unused = vec![]; + LocationRule::Indexed { + location: KnownU32(map_access + offset).to_value_bucket(&mut unused).allocate(), + template_header: Some(name), } } else { let mut unused = vec![]; From f70978d92e940c0ab5ecb6bdd97c9708940c0d48 Mon Sep 17 00:00:00 2001 From: Timothy Hoffman <4001421+tim-hoffman@users.noreply.github.com> Date: Wed, 16 Aug 2023 11:14:22 -0500 Subject: [PATCH 06/12] move error printout to the end (after dump) (#43) also add template vs. function to the "Running" debug line --- circuit_passes/src/bucket_interpreter/env.rs | 2 +- circuit_passes/src/passes/memory.rs | 2 +- code_producers/src/llvm_elements/mod.rs | 10 +++------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/circuit_passes/src/bucket_interpreter/env.rs b/circuit_passes/src/bucket_interpreter/env.rs index 7c584ff7c..f94292b46 100644 --- a/circuit_passes/src/bucket_interpreter/env.rs +++ b/circuit_passes/src/bucket_interpreter/env.rs @@ -238,7 +238,7 @@ impl<'a> Env<'a> { observe: bool, ) -> Value { if cfg!(debug_assertions) { - println!("Running {}", name); + println!("Running function {}", name); } let code = &self.functions_library[name].body; let mut function_env = diff --git a/circuit_passes/src/passes/memory.rs b/circuit_passes/src/passes/memory.rs index fc41322cf..55b8631b3 100644 --- a/circuit_passes/src/passes/memory.rs +++ b/circuit_passes/src/passes/memory.rs @@ -48,7 +48,7 @@ impl PassMemory { pub fn run_template(&self, observer: &dyn InterpreterObserver, template: &TemplateCode) { assert!(!self.current_scope.is_empty()); if cfg!(debug_assertions) { - println!("Running {}", self.current_scope); + println!("Running template {}", self.current_scope); } let interpreter = self.build_interpreter(observer); let env = Env::new(&self.templates_library, &self.functions_library, self); diff --git a/code_producers/src/llvm_elements/mod.rs b/code_producers/src/llvm_elements/mod.rs index 57a7a66c6..f78aa6cb1 100644 --- a/code_producers/src/llvm_elements/mod.rs +++ b/code_producers/src/llvm_elements/mod.rs @@ -43,10 +43,7 @@ pub trait BodyCtx<'a> { index: IntValue<'a>, ) -> AnyValueEnum<'a>; - fn get_variable_array( - &self, - producer: &dyn LLVMIRProducer<'a>, - ) -> AnyValueEnum<'a>; + fn get_variable_array(&self, producer: &dyn LLVMIRProducer<'a>) -> AnyValueEnum<'a>; } pub trait LLVMIRProducer<'a> { @@ -63,7 +60,6 @@ pub trait LLVMIRProducer<'a> { pub type IndexMapping = HashMap>; - #[derive(Default, Eq, PartialEq, Debug)] pub struct LLVMCircuitData { pub field_tracking: Vec, @@ -294,13 +290,13 @@ impl<'a> LLVM<'a> { } // Run module verification self.module.verify().map_err(|llvm_err| { + eprintln!("Generated LLVM:"); + self.module.print_to_stderr(); eprintln!( "{}: {}", Colour::Red.paint("LLVM Module verification failed"), llvm_err.to_string() ); - eprintln!("Generated LLVM:"); - self.module.print_to_stderr(); })?; // Verify that bitcode can be written, parsed, and re-verified { From ca4f00c79a6cf3cc0f7758f65206c5eb3ece5e33 Mon Sep 17 00:00:00 2001 From: Ian Neal Date: Wed, 16 Aug 2023 16:51:22 -0400 Subject: [PATCH 07/12] Ensure br is only called with i1 (#45) --- circom/tests/controlflow/van544.circom | 22 +++++++++++++++++++ .../src/llvm_elements/instructions.rs | 9 +++++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 circom/tests/controlflow/van544.circom diff --git a/circom/tests/controlflow/van544.circom b/circom/tests/controlflow/van544.circom new file mode 100644 index 000000000..40d4acc70 --- /dev/null +++ b/circom/tests/controlflow/van544.circom @@ -0,0 +1,22 @@ +pragma circom 2.0.0; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s + +template Conditional() { + signal input inp; + var q; + if (inp) { + q = 0; + } else { + q = 1; + } +} + +component main = Conditional(); + +//CHECK-LABEL: define void @Conditional_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %0) +//CHECK: %[[INP_PTR:.*]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0 +//CHECK: %[[INP:.*]] = load i256, i256* %2 +//CHECK: %[[COND:.*]] = icmp ne i256 %[[INP]], 0 +//CHECK: br i1 %[[COND]], label %if.then, label %if.else diff --git a/code_producers/src/llvm_elements/instructions.rs b/code_producers/src/llvm_elements/instructions.rs index a2c05c06f..d64e1e378 100644 --- a/code_producers/src/llvm_elements/instructions.rs +++ b/code_producers/src/llvm_elements/instructions.rs @@ -548,10 +548,17 @@ pub fn create_conditional_branch<'a>( then_block: BasicBlock<'a>, else_block: BasicBlock<'a>, ) -> AnyValueEnum<'a> { + let comparison_type = comparison.get_type(); + let bool_ty = producer.llvm().module.get_context().bool_type(); + let bool_comparison = if comparison_type != bool_ty { + create_neq(producer, comparison, comparison_type.const_zero()).into_int_value() + } else { + comparison + }; producer .llvm() .builder - .build_conditional_branch(comparison, then_block, else_block) + .build_conditional_branch(bool_comparison, then_block, else_block) .as_any_value_enum() } From 0e67892c26d91b5b3e30bb670360be6fe8a75144 Mon Sep 17 00:00:00 2001 From: Ian Neal Date: Thu, 17 Aug 2023 17:02:05 -0400 Subject: [PATCH 08/12] [VAN-543] unknown input status (#44) * Add minimized test case * Add InputStatus resolution for final return data --- circom/tests/subcmps/subcmps2.circom | 43 +++++++++++++++ .../deterministic_subcomponent_invocation.rs | 52 +++++++++++-------- .../store_bucket.rs | 2 +- 3 files changed, 75 insertions(+), 22 deletions(-) create mode 100644 circom/tests/subcmps/subcmps2.circom diff --git a/circom/tests/subcmps/subcmps2.circom b/circom/tests/subcmps/subcmps2.circom new file mode 100644 index 000000000..6f1668e7e --- /dev/null +++ b/circom/tests/subcmps/subcmps2.circom @@ -0,0 +1,43 @@ +pragma circom 2.0.6; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s + +template Sum(n) { + signal input inp[n]; + signal output outp; + + var s = 0; + + for (var i = 0; i < n; i++) { + s += inp[i]; + } + + outp <== s; +} + +function nop(i) { + return i; +} + +template Caller() { + signal input inp[4]; + signal output outp; + + component s = Sum(4); + + for (var i = 0; i < 4; i++) { + s.inp[i] <== nop(inp[i]); + } + + outp <== s.outp; +} + +component main = Caller(); + +//CHECK-LABEL: define void @Caller_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %0) +//CHECK: %[[CALL_VAL:call\.nop_[0-3]]] = call i256 @nop_{{[0-3]}}(i256* %6) +//CHECK: %[[SUBCMP_PTR:.*]] = getelementptr [1 x { [0 x i256]*, i32 }], [1 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 0, i32 {{[0-3]}} +//CHECK: %[[SUBCMP:.*]] = load [0 x i256]*, [0 x i256]** %[[SUBCMP_PTR]] +//CHECK: %[[SUBCMP_INP:.*]] = getelementptr [0 x i256], [0 x i256]* %[[SUBCMP]], i32 0, i32 {{[1-4]}} +//CHECK: store i256 %[[CALL_VAL]], i256* %[[SUBCMP_INP]] diff --git a/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs b/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs index aa7fa6d30..949bbda55 100644 --- a/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs +++ b/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs @@ -22,38 +22,42 @@ impl DeterministicSubCmpInvokePass { replacements: Default::default(), } } -} - -impl InterpreterObserver for DeterministicSubCmpInvokePass { - fn on_value_bucket(&self, _bucket: &ValueBucket, _env: &Env) -> bool { - true - } - - fn on_load_bucket(&self, _bucket: &LoadBucket, _env: &Env) -> bool { - true - } - fn on_store_bucket(&self, bucket: &StoreBucket, env: &Env) -> bool { - let env = env.clone(); - let mem = self.memory.borrow(); - let interpreter = mem.build_interpreter(self); - // If the address of the subcomponent input information is unk, then - // If executing this store bucket would result in calling the subcomponent we replace it with Last + pub fn try_resolve_input_status(&self, address_type: &AddressType, env: &Env) { + // If the address of the subcomponent input information is unknown, then + // If executing this instruction would result in calling the subcomponent we replace it with Last // Will result in calling if the counter is at one because after the execution it will be 0 // If not replace with NoLast if let AddressType::SubcmpSignal { input_information: InputInformation::Input { status: StatusInput::Unknown }, cmp_address, .. - } = &bucket.dest_address_type + } = address_type { + let env = env.clone(); + let mem = self.memory.borrow(); + let interpreter = mem.build_interpreter(self); let (addr, env) = interpreter.execute_instruction(cmp_address, env, false); let addr = addr - .expect("cmp_address instruction in StoreBucket SubcmpSignal must produce a value!") + .expect("cmp_address instruction in SubcmpSignal must produce a value!") .get_u32(); let new_status = if env.subcmp_counter_equal_to(addr, 1) { Last } else { NoLast }; - self.replacements.borrow_mut().insert(bucket.dest_address_type.clone(), new_status); + self.replacements.borrow_mut().insert(address_type.clone(), new_status); } + } +} + +impl InterpreterObserver for DeterministicSubCmpInvokePass { + fn on_value_bucket(&self, _bucket: &ValueBucket, _env: &Env) -> bool { + true + } + + fn on_load_bucket(&self, _bucket: &LoadBucket, _env: &Env) -> bool { + true + } + + fn on_store_bucket(&self, bucket: &StoreBucket, env: &Env) -> bool { + self.try_resolve_input_status(&bucket.dest_address_type, env); true } @@ -89,8 +93,14 @@ impl InterpreterObserver for DeterministicSubCmpInvokePass { true } - fn on_call_bucket(&self, _bucket: &CallBucket, _env: &Env) -> bool { - true + fn on_call_bucket(&self, bucket: &CallBucket, env: &Env) -> bool { + match &bucket.return_info { + ReturnType::Intermediate {..} => true, + ReturnType::Final(data) => { + self.try_resolve_input_status(&data.dest_address_type, env); + true + }, + } } fn on_branch_bucket(&self, _bucket: &BranchBucket, _env: &Env) -> bool { diff --git a/compiler/src/intermediate_representation/store_bucket.rs b/compiler/src/intermediate_representation/store_bucket.rs index 67ef371d1..73982ebe4 100644 --- a/compiler/src/intermediate_representation/store_bucket.rs +++ b/compiler/src/intermediate_representation/store_bucket.rs @@ -189,7 +189,7 @@ impl StoreBucket{ match status { StatusInput::Last => { let run_fn = run_fn_name(sub_cmp_name.expect("Could not get the name of the subcomponent")); - // If we reach this point gep is the address of the subcomponent so we ca just reuse it + // If we reach this point gep is the address of the subcomponent so we can just reuse it let addr = cmp_address.produce_llvm_ir(producer).expect("The address of a subcomponent must yield a value!"); let subcmp = producer.template_ctx().load_subcmp_addr(producer, addr); create_call(producer, run_fn.as_str(), &[subcmp.into()]); From 653e3c406e4abe5da068f31227b0d5bfbd6806fc Mon Sep 17 00:00:00 2001 From: Timothy Hoffman <4001421+tim-hoffman@users.noreply.github.com> Date: Fri, 18 Aug 2023 15:38:56 -0500 Subject: [PATCH 09/12] Add running pass name debug print (#46) --- circuit_passes/src/passes/conditional_flattening.rs | 4 ++++ .../src/passes/deterministic_subcomponent_invocation.rs | 4 ++++ circuit_passes/src/passes/loop_unroll.rs | 4 ++++ circuit_passes/src/passes/mapped_to_indexed.rs | 4 ++++ circuit_passes/src/passes/mod.rs | 5 +++++ circuit_passes/src/passes/simplification.rs | 4 ++++ circuit_passes/src/passes/unknown_index_sanitization.rs | 4 ++++ 7 files changed, 29 insertions(+) diff --git a/circuit_passes/src/passes/conditional_flattening.rs b/circuit_passes/src/passes/conditional_flattening.rs index 63ea9b185..84e32ed5d 100644 --- a/circuit_passes/src/passes/conditional_flattening.rs +++ b/circuit_passes/src/passes/conditional_flattening.rs @@ -107,6 +107,10 @@ impl InterpreterObserver for ConditionalFlattening { } impl CircuitTransformationPass for ConditionalFlattening { + fn name(&self) -> &str { + "ConditionalFlattening" + } + fn pre_hook_circuit(&self, circuit: &Circuit) { self.memory.borrow_mut().fill_from_circuit(circuit); } diff --git a/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs b/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs index 949bbda55..cb6448fcb 100644 --- a/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs +++ b/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs @@ -125,6 +125,10 @@ impl InterpreterObserver for DeterministicSubCmpInvokePass { } impl CircuitTransformationPass for DeterministicSubCmpInvokePass { + fn name(&self) -> &str { + "DeterministicSubCmpInvokePass" + } + fn pre_hook_circuit(&self, circuit: &Circuit) { self.memory.borrow_mut().fill_from_circuit(circuit); } diff --git a/circuit_passes/src/passes/loop_unroll.rs b/circuit_passes/src/passes/loop_unroll.rs index 318b64dbc..8aed5c73b 100644 --- a/circuit_passes/src/passes/loop_unroll.rs +++ b/circuit_passes/src/passes/loop_unroll.rs @@ -144,6 +144,10 @@ impl InterpreterObserver for LoopUnrollPass { } impl CircuitTransformationPass for LoopUnrollPass { + fn name(&self) -> &str { + "LoopUnrollPass" + } + fn pre_hook_circuit(&self, circuit: &Circuit) { self.memory.borrow_mut().fill_from_circuit(circuit); } diff --git a/circuit_passes/src/passes/mapped_to_indexed.rs b/circuit_passes/src/passes/mapped_to_indexed.rs index 7712f2b3b..4a7df6b32 100644 --- a/circuit_passes/src/passes/mapped_to_indexed.rs +++ b/circuit_passes/src/passes/mapped_to_indexed.rs @@ -153,6 +153,10 @@ impl InterpreterObserver for MappedToIndexedPass { } impl CircuitTransformationPass for MappedToIndexedPass { + fn name(&self) -> &str { + "MappedToIndexedPass" + } + fn get_updated_field_constants(&self) -> Vec { self.memory.borrow().constant_fields.clone() } diff --git a/circuit_passes/src/passes/mod.rs b/circuit_passes/src/passes/mod.rs index 7aef0c06c..7f8db765d 100644 --- a/circuit_passes/src/passes/mod.rs +++ b/circuit_passes/src/passes/mod.rs @@ -28,6 +28,8 @@ macro_rules! pre_hook { } pub trait CircuitTransformationPass { + fn name(&self) -> &str; + fn transform_circuit(&self, circuit: &Circuit) -> Circuit { self.pre_hook_circuit(&circuit); let templates = circuit.templates.iter().map(|t| self.transform_template(t)).collect(); @@ -430,6 +432,9 @@ impl PassManager { pub fn transform_circuit(&self, circuit: Circuit) -> Circuit { let mut transformed_circuit = circuit; for pass in self.passes.borrow().iter() { + if cfg!(debug_assertions) { + println!("Do {}...", pass.name()); + } transformed_circuit = pass.transform_circuit(&transformed_circuit); assert_unique_ids_in_circuit(&transformed_circuit); } diff --git a/circuit_passes/src/passes/simplification.rs b/circuit_passes/src/passes/simplification.rs index 0f30d250b..4868231da 100644 --- a/circuit_passes/src/passes/simplification.rs +++ b/circuit_passes/src/passes/simplification.rs @@ -118,6 +118,10 @@ impl InterpreterObserver for SimplificationPass { } impl CircuitTransformationPass for SimplificationPass { + fn name(&self) -> &str { + "SimplificationPass" + } + fn get_updated_field_constants(&self) -> Vec { self.memory.borrow().constant_fields.clone() } diff --git a/circuit_passes/src/passes/unknown_index_sanitization.rs b/circuit_passes/src/passes/unknown_index_sanitization.rs index 31eb8a021..68d92da9d 100644 --- a/circuit_passes/src/passes/unknown_index_sanitization.rs +++ b/circuit_passes/src/passes/unknown_index_sanitization.rs @@ -249,6 +249,10 @@ impl InterpreterObserver for UnknownIndexSanitizationPass { } impl CircuitTransformationPass for UnknownIndexSanitizationPass { + fn name(&self) -> &str { + "UnknownIndexSanitizationPass" + } + fn transform_load_bucket(&self, bucket: &LoadBucket) -> InstructionPointer { let bounded_fn_symbol = match self.load_replacements.borrow().get(bucket) { Some(index_range) => Some(get_array_load_symbol(index_range)), From 8f93b2e5fba7a46970c76b794502912d5f3b4423 Mon Sep 17 00:00:00 2001 From: Ian Neal Date: Fri, 18 Aug 2023 18:53:15 -0400 Subject: [PATCH 10/12] [VAN-503] Convert to/from i1 as needed (#47) * Add conversions for boolean <=> bigint type as needed Co-authored-by: Timothy Hoffman <4001421+tim-hoffman@users.noreply.github.com> --- circom/tests/type_conversions/bool_1.circom | 22 ++++ circom/tests/type_conversions/bool_2.circom | 31 +++++ circom/tests/type_conversions/bool_3.circom | 25 +++++ circom/tests/type_conversions/bool_4.circom | 27 +++++ .../src/llvm_elements/instructions.rs | 106 ++++++++++++++++-- 5 files changed, 199 insertions(+), 12 deletions(-) create mode 100644 circom/tests/type_conversions/bool_1.circom create mode 100644 circom/tests/type_conversions/bool_2.circom create mode 100644 circom/tests/type_conversions/bool_3.circom create mode 100644 circom/tests/type_conversions/bool_4.circom diff --git a/circom/tests/type_conversions/bool_1.circom b/circom/tests/type_conversions/bool_1.circom new file mode 100644 index 000000000..9225add4a --- /dev/null +++ b/circom/tests/type_conversions/bool_1.circom @@ -0,0 +1,22 @@ +pragma circom 2.0.0; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck --enable-var-scope %s + +function binop_comp(a, b) { + return a > b; +} + +template A(x) { + signal input in; + signal output out; + + out <-- binop_comp(in, x); +} + +component main = A(5); + +//CHECK-LABEL: define i256 @binop_comp_{{[0-9]+}} +//CHECK-SAME: (i256* %0) +//CHECK: %call.fr_gt = call i1 @fr_gt(i256 %{{[0-9]+}}, i256 %{{[0-9]+}}) +//CHECK: %[[RET:[0-9]+]] = zext i1 %call.fr_gt to i256 +//CHECK: ret i256 %[[RET]] diff --git a/circom/tests/type_conversions/bool_2.circom b/circom/tests/type_conversions/bool_2.circom new file mode 100644 index 000000000..3836e98f0 --- /dev/null +++ b/circom/tests/type_conversions/bool_2.circom @@ -0,0 +1,31 @@ +pragma circom 2.0.0; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck --enable-var-scope %s + +function binop_bool(a, b) { + return a || b; +} + +template A(x) { + signal input in; + signal output out; + + var temp; + if (binop_bool(in, x)) { + temp = 1; + } else { + temp = 0; + } + out <-- temp; + + //Essentially equivalent code: + // out <-- binop_bool(in, x); +} + +component main = A(555); + +//CHECK-LABEL: define i256 @binop_bool_{{[0-9]+}} +//CHECK-SAME: (i256* %0) +//CHECK: %call.fr_logic_or = call i1 @fr_logic_or(i1 %{{[0-9]+}}, i1 %{{[0-9]+}}) +//CHECK: %[[RET:[0-9]+]] = zext i1 %call.fr_logic_or to i256 +//CHECK: ret i256 %[[RET]] diff --git a/circom/tests/type_conversions/bool_3.circom b/circom/tests/type_conversions/bool_3.circom new file mode 100644 index 000000000..d3f2103e7 --- /dev/null +++ b/circom/tests/type_conversions/bool_3.circom @@ -0,0 +1,25 @@ +pragma circom 2.0.0; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck --enable-var-scope %s + +template A(x) { + signal input in; + signal output out; + + var z = 0; + if (in || x) { + z = 1; + } + out <-- z; +} + +component main = A(99); + +//CHECK-LABEL: define void @A_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %0) +//CHECK: branch{{[0-9]+}}: +//CHECK: %[[VAL_PTR:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 1 +//CHECK: %[[VAL:[0-9]+]] = load i256, i256* %[[VAL_PTR]] +//CHECK: %[[BOOL:[0-9]+]] = icmp ne i256 %[[VAL]], 0 +//CHECK: %call.fr_logic_or = call i1 @fr_logic_or(i1 %[[BOOL]], i1 true) +//CHECK: br i1 %call.fr_logic_or, label %if.then, label %if.else diff --git a/circom/tests/type_conversions/bool_4.circom b/circom/tests/type_conversions/bool_4.circom new file mode 100644 index 000000000..aadcd3cf3 --- /dev/null +++ b/circom/tests/type_conversions/bool_4.circom @@ -0,0 +1,27 @@ +pragma circom 2.0.0; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck --enable-var-scope %s + +function binop_bool_array(a, b) { + var arr[10]; + for (var i = 0; i < 10; i++) { + arr[i] = a[i] || b[i]; + } + return arr; +} + +template A() { + signal input in1[10]; + signal input in2[10]; + signal output out[10]; + + out <-- binop_bool_array(in1, in2); +} + +component main = A(); + +//CHECK-LABEL: define void @binop_bool_array_{{[0-9]+}} +//CHECK-SAME: (i256* %0) +//CHECK: %call.fr_logic_or = call i1 @fr_logic_or(i1 %{{[0-9]+}}, i1 %{{[0-9]+}}) +//CHECK: %[[VAL:[0-9]+]] = zext i1 %call.fr_logic_or to i256 +//CHECK: store i256 %[[VAL]], i256* %{{[0-9]+}} \ No newline at end of file diff --git a/code_producers/src/llvm_elements/instructions.rs b/code_producers/src/llvm_elements/instructions.rs index d64e1e378..1496453be 100644 --- a/code_producers/src/llvm_elements/instructions.rs +++ b/code_producers/src/llvm_elements/instructions.rs @@ -1,12 +1,17 @@ use inkwell::basic_block::BasicBlock; use inkwell::IntPredicate::{EQ, NE, SLT, SGT, SLE, SGE}; -use inkwell::types::{AnyTypeEnum, PointerType}; -use inkwell::values::{AnyValue, AnyValueEnum, BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, InstructionOpcode, InstructionValue, IntMathValue, IntValue, PhiValue, PointerValue}; +use inkwell::types::{AnyTypeEnum, PointerType, IntType}; +use inkwell::values::{ + AnyValue, AnyValueEnum, BasicMetadataValueEnum, BasicValue, BasicValueEnum, FunctionValue, + InstructionOpcode, InstructionValue, IntMathValue, IntValue, PhiValue, PointerValue, +}; use crate::llvm_elements::{LLVMIRProducer}; use crate::llvm_elements::fr::{FR_MUL_FN_NAME, FR_LT_FN_NAME}; use crate::llvm_elements::functions::create_bb; use crate::llvm_elements::types::{bigint_type, i32_type}; +use super::types::bool_type; + // bigint abv; // if (rhs < 0) // abv = -rhs; @@ -437,6 +442,50 @@ pub fn create_bit_xor<'a, T: IntMathValue<'a>>( create_bit_xor_with_name(producer, lhs, rhs, "") } +pub fn ensure_bool_with_name<'a, T: IntMathValue<'a>>( + producer: &dyn LLVMIRProducer<'a>, + val: T, + name: &str, +) -> AnyValueEnum<'a> { + let int_val = val.as_basic_value_enum().into_int_value(); + if int_val.get_type() != bool_type(producer) { + create_neq_with_name(producer, int_val, bigint_type(producer).const_zero(), name) + } else { + val.as_any_value_enum() + } +} + +pub fn ensure_bool<'a, T: IntMathValue<'a>>( + producer: &dyn LLVMIRProducer<'a>, + val: T, +) -> AnyValueEnum<'a> { + ensure_bool_with_name(producer, val, "") +} + +pub fn ensure_int_type_match<'a>( + producer: &dyn LLVMIRProducer<'a>, + val: IntValue<'a>, + ty: IntType<'a>, +) -> IntValue<'a> { + if val.get_type() == ty { + // No conversion needed + val + } else if val.get_type() == bool_type(producer) { + // Zero extend + producer.llvm().builder.build_int_z_extend(val, ty, "") + } else if ty == bool_type(producer) { + // Convert to bool + ensure_bool(producer, val).into_int_value() + } else { + panic!( + "Unhandled int conversion of value '{:?}': {:?} to {:?} not supported!", + val, + val.get_type(), + ty + ) + } +} + pub fn create_logic_and_with_name<'a, T: IntMathValue<'a>>( producer: &dyn LLVMIRProducer<'a>, lhs: T, @@ -493,7 +542,10 @@ pub fn create_store<'a>( ) -> AnyValueEnum<'a> { match value { AnyValueEnum::ArrayValue(v) => producer.llvm().builder.build_store(ptr, v), - AnyValueEnum::IntValue(v) => producer.llvm().builder.build_store(ptr, v), + AnyValueEnum::IntValue(v) => { + let store_ty = ptr.get_type().get_element_type().into_int_type(); + producer.llvm().builder.build_store(ptr, ensure_int_type_match(producer, v, store_ty)) + } AnyValueEnum::FloatValue(v) => producer.llvm().builder.build_store(ptr, v), AnyValueEnum::PointerValue(v) => producer.llvm().builder.build_store(ptr, v), AnyValueEnum::StructValue(v) => producer.llvm().builder.build_store(ptr, v), @@ -511,7 +563,26 @@ pub fn create_return<'a, V: BasicValue<'a>>( producer: &dyn LLVMIRProducer<'a>, val: V, ) -> AnyValueEnum<'a> { - producer.llvm().builder.build_return(Some(&val)).as_any_value_enum() + let f = producer + .llvm() + .builder + .get_insert_block() + .expect("no current block!") + .get_parent() + .expect("no current function!"); + let ret_ty = + f.get_type().get_return_type().expect("non-void function should have a return type!"); + let ret_val = if ret_ty.is_int_type() { + ensure_int_type_match( + producer, + val.as_basic_value_enum().into_int_value(), + ret_ty.into_int_type(), + ) + .as_basic_value_enum() + } else { + val.as_basic_value_enum() + }; + producer.llvm().builder.build_return(Some(&ret_val)).as_any_value_enum() } pub fn create_br<'a>(producer: &dyn LLVMIRProducer<'a>, bb: BasicBlock<'a>) -> AnyValueEnum<'a> { @@ -535,10 +606,27 @@ pub fn create_call<'a>( arguments: &[BasicMetadataValueEnum<'a>], ) -> AnyValueEnum<'a> { let f = find_function(producer, name); + let params = f.get_params(); + let checked_arguments: Vec> = arguments + .into_iter() + .zip(params.into_iter()) + .map(|(arg, param)| { + if arg.is_int_value() && param.is_int_value() { + ensure_int_type_match( + producer, + arg.into_int_value(), + param.get_type().into_int_type(), + ) + .into() + } else { + arg.clone() + } + }) + .collect(); producer .llvm() .builder - .build_call(f, arguments, format!("call.{}", name).as_str()) + .build_call(f, &checked_arguments, format!("call.{}", name).as_str()) .as_any_value_enum() } @@ -548,13 +636,7 @@ pub fn create_conditional_branch<'a>( then_block: BasicBlock<'a>, else_block: BasicBlock<'a>, ) -> AnyValueEnum<'a> { - let comparison_type = comparison.get_type(); - let bool_ty = producer.llvm().module.get_context().bool_type(); - let bool_comparison = if comparison_type != bool_ty { - create_neq(producer, comparison, comparison_type.const_zero()).into_int_value() - } else { - comparison - }; + let bool_comparison = ensure_bool(producer, comparison).into_int_value(); producer .llvm() .builder From 58c3c943d6d2b336877a36551fed784339808392 Mon Sep 17 00:00:00 2001 From: Timothy Hoffman <4001421+tim-hoffman@users.noreply.github.com> Date: Tue, 22 Aug 2023 16:49:10 -0500 Subject: [PATCH 11/12] apply auto-formatting (#48) --- circom/build.rs | 16 +- circuit_passes/src/bucket_interpreter/mod.rs | 307 +++++++++++++----- .../src/bucket_interpreter/operations.rs | 14 +- .../deterministic_subcomponent_invocation.rs | 4 +- .../src/passes/mapped_to_indexed.rs | 56 ++-- .../src/llvm_elements/instructions.rs | 9 +- code_producers/src/llvm_elements/template.rs | 25 +- .../block_bucket.rs | 20 +- .../constraint_bucket.rs | 81 +++-- .../intermediate_representation/nop_bucket.rs | 11 +- parser/src/errors.rs | 100 +++--- 11 files changed, 408 insertions(+), 235 deletions(-) diff --git a/circom/build.rs b/circom/build.rs index 7f7486fbf..503b9cde8 100644 --- a/circom/build.rs +++ b/circom/build.rs @@ -14,19 +14,27 @@ fn main() { let path = entry.unwrap(); create_dir_all(Path::new(&out_dir).join(path.parent().unwrap())).unwrap(); copy(path.clone(), Path::new(&out_dir).join(path.clone())).unwrap(); - let test_name = path.to_str().unwrap() + let test_name = path + .to_str() + .unwrap() .replace("/", "_") .replace(".circom", "") .replace("-", "_") .to_lowercase(); - test_code = format!(" + test_code = format!( + " {} #[test] fn {}() -> LitResult<()> {{ lit_test(include_str!(\"{}\"), \"{}\") - }}", test_code, test_name, path.to_str().unwrap(), test_name); + }}", + test_code, + test_name, + path.to_str().unwrap(), + test_name + ); } generate_file(&dest_path, test_code.as_bytes()); @@ -35,4 +43,4 @@ fn main() { fn generate_file>(path: P, text: &[u8]) { let mut f = File::create(path).unwrap(); f.write_all(text).unwrap() -} \ No newline at end of file +} diff --git a/circuit_passes/src/bucket_interpreter/mod.rs b/circuit_passes/src/bucket_interpreter/mod.rs index cb1c7d800..c5ff9627f 100644 --- a/circuit_passes/src/bucket_interpreter/mod.rs +++ b/circuit_passes/src/bucket_interpreter/mod.rs @@ -16,7 +16,6 @@ use crate::bucket_interpreter::operations::compute_offset; use crate::bucket_interpreter::value::{JoinSemiLattice, Value}; use crate::bucket_interpreter::value::Value::{KnownBigInt, KnownU32, Unknown}; - pub struct BucketInterpreter<'a> { _scope: &'a String, _prime: &'a String, @@ -26,7 +25,7 @@ pub struct BucketInterpreter<'a> { p: BigInt, signal_index_mapping: &'a IndexMapping, variables_index_mapping: &'a IndexMapping, - component_addr_index_mapping: &'a IndexMapping + component_addr_index_mapping: &'a IndexMapping, } pub type R<'a> = (Option, Env<'a>); @@ -36,7 +35,7 @@ impl JoinSemiLattice for Option { match (self, other) { (x, None) => x.clone(), (None, x) => x.clone(), - (Some(x), Some(y)) => Some(x.join(y)) + (Some(x), Some(y)) => Some(x.join(y)), } } } @@ -47,7 +46,6 @@ impl JoinSemiLattice for R<'_> { } } - impl<'a> BucketInterpreter<'a> { pub fn init( scope: &'a String, @@ -57,7 +55,7 @@ impl<'a> BucketInterpreter<'a> { io_map: &'a TemplateInstanceIOMap, signal_index_mapping: &'a IndexMapping, variables_index_mapping: &'a IndexMapping, - component_addr_index_mapping: &'a IndexMapping + component_addr_index_mapping: &'a IndexMapping, ) -> Self { BucketInterpreter { _scope: scope, @@ -68,7 +66,7 @@ impl<'a> BucketInterpreter<'a> { p: UsefulConstants::new(prime).get_p().clone(), signal_index_mapping, variables_index_mapping, - component_addr_index_mapping + component_addr_index_mapping, } } @@ -78,23 +76,33 @@ impl<'a> BucketInterpreter<'a> { let (idx, _) = self.execute_instruction(location, env.clone(), false); idx.expect("LocationRule must produce a value!").get_u32() } - LocationRule::Mapped { .. } => unreachable!() + LocationRule::Mapped { .. } => unreachable!(), } } - fn get_write_operations_in_store_bucket(&self, bucket: &StoreBucket, - vars: &mut Vec, - signals: &mut Vec, - subcmps: &mut Vec, - env: &Env) { + fn get_write_operations_in_store_bucket( + &self, + bucket: &StoreBucket, + vars: &mut Vec, + signals: &mut Vec, + subcmps: &mut Vec, + env: &Env, + ) { match bucket.dest_address_type { AddressType::Variable => { let idx = self.get_id_from_indexed_location(&bucket.dest, env); - let indices = self.variables_index_mapping.get(&idx).expect( - format!("Could not get idx {idx} from mapping. Min key {:?}. Max key {:?}", + let indices = self + .variables_index_mapping + .get(&idx) + .expect( + format!( + "Could not get idx {idx} from mapping. Min key {:?}. Max key {:?}", self.variables_index_mapping.keys().min(), - self.variables_index_mapping.keys().max()).as_str() - ).clone(); + self.variables_index_mapping.keys().max() + ) + .as_str(), + ) + .clone(); for index in indices { vars.push(index); } @@ -122,33 +130,49 @@ impl<'a> BucketInterpreter<'a> { vars: &mut Vec, signals: &mut Vec, subcmps: &mut Vec, - env: &Env + env: &Env, ) { match inst { Instruction::Value(_) => {} // Cannot write - Instruction::Load(_) => {} // Should not have a StoreBucket inside + Instruction::Load(_) => {} // Should not have a StoreBucket inside Instruction::Store(bucket) => { self.get_write_operations_in_store_bucket(bucket, vars, signals, subcmps, env) } Instruction::Compute(_) => {} // Should not have a StoreBucket inside - Instruction::Call(_) => {} // Should not have a StoreBucket as argument + Instruction::Call(_) => {} // Should not have a StoreBucket as argument Instruction::Branch(bucket) => { - self.get_write_operations_in_body_rec(&bucket.if_branch, vars, signals, subcmps, env); - self.get_write_operations_in_body_rec(&bucket.else_branch, vars, signals, subcmps, env); + self.get_write_operations_in_body_rec( + &bucket.if_branch, + vars, + signals, + subcmps, + env, + ); + self.get_write_operations_in_body_rec( + &bucket.else_branch, + vars, + signals, + subcmps, + env, + ); } Instruction::Return(_) => {} // Should not have a StoreBucket in the return expression Instruction::Assert(_) => {} // Should not have a StoreBucket inside - Instruction::Log(_) => {} // Should not have a StoreBucket inside + Instruction::Log(_) => {} // Should not have a StoreBucket inside Instruction::Loop(bucket) => { self.get_write_operations_in_body_rec(&bucket.body, vars, signals, subcmps, env) } Instruction::CreateCmp(_) => {} // Should not have a StoreBucket inside - Instruction::Constraint(bucket) => { - self.get_write_operations_in_inst_rec(match bucket { + Instruction::Constraint(bucket) => self.get_write_operations_in_inst_rec( + match bucket { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i - }, vars, signals, subcmps, env) - } + ConstraintBucket::Equality(i) => i, + }, + vars, + signals, + subcmps, + env, + ), Instruction::Block(bucket) => { self.get_write_operations_in_body_rec(&bucket.body, vars, signals, subcmps, env) } @@ -162,7 +186,7 @@ impl<'a> BucketInterpreter<'a> { vars: &mut Vec, signals: &mut Vec, subcmps: &mut Vec, - env: &Env + env: &Env, ) { for inst in body { self.get_write_operations_in_inst_rec(inst, vars, signals, subcmps, env); @@ -173,7 +197,11 @@ impl<'a> BucketInterpreter<'a> { /// 0: Indices of variables /// 1: Indices of signals /// 2: Indices of subcmps - fn get_write_operations_in_body(&self, body: &InstructionList, env: &Env) -> (Vec, Vec, Vec) { + fn get_write_operations_in_body( + &self, + body: &InstructionList, + env: &Env, + ) -> (Vec, Vec, Vec) { let mut vars = vec![]; let mut signals = vec![]; let mut subcmps = vec![]; @@ -183,7 +211,12 @@ impl<'a> BucketInterpreter<'a> { return (vars, signals, subcmps); } - pub fn execute_value_bucket<'env>(&self, bucket: &ValueBucket, env: Env<'env>, _observe: bool) -> R<'env> { + pub fn execute_value_bucket<'env>( + &self, + bucket: &ValueBucket, + env: Env<'env>, + _observe: bool, + ) -> R<'env> { ( Some(match bucket.parse_as { ValueType::BigInt => { @@ -195,18 +228,25 @@ impl<'a> BucketInterpreter<'a> { } ValueType::U32 => KnownU32(bucket.value), }), - env + env, ) } - pub fn execute_load_bucket<'env>(&self, bucket: &'env LoadBucket, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_load_bucket<'env>( + &self, + bucket: &'env LoadBucket, + env: Env<'env>, + observe: bool, + ) -> R<'env> { match &bucket.address_type { AddressType::Variable => { let continue_observing = if observe { self.observer.on_location_rule(&bucket.src, &env) } else { false }; let (idx, env) = match &bucket.src { - LocationRule::Indexed { location, .. } => self.execute_instruction(location, env, continue_observing), - LocationRule::Mapped { .. } => unreachable!() + LocationRule::Indexed { location, .. } => { + self.execute_instruction(location, env, continue_observing) + } + LocationRule::Mapped { .. } => unreachable!(), }; let idx = idx.expect("Indexed location must produce a value!"); if idx.is_unknown() { @@ -214,13 +254,15 @@ impl<'a> BucketInterpreter<'a> { } else { (Some(env.get_var(idx.get_u32())), env) } - }, + } AddressType::Signal => { let continue_observing = if observe { self.observer.on_location_rule(&bucket.src, &env) } else { false }; let (idx, env) = match &bucket.src { - LocationRule::Indexed { location, .. } => self.execute_instruction(location, env, continue_observing), - LocationRule::Mapped { .. } => unreachable!() + LocationRule::Indexed { location, .. } => { + self.execute_instruction(location, env, continue_observing) + } + LocationRule::Mapped { .. } => unreachable!(), }; let idx = idx.expect("Indexed location must produce a value!"); if idx.is_unknown() { @@ -228,7 +270,7 @@ impl<'a> BucketInterpreter<'a> { } else { (Some(env.get_signal(idx.get_u32())), env) } - }, + } AddressType::SubcmpSignal { cmp_address, .. } => { let (addr, env) = self.execute_instruction(cmp_address, env, observe); let addr = addr @@ -240,18 +282,23 @@ impl<'a> BucketInterpreter<'a> { if observe { self.observer.on_location_rule(&bucket.src, &env) } else { false }; let (idx, env) = match &bucket.src { LocationRule::Indexed { location, .. } => { - let (idx, env) = self.execute_instruction(location, env, continue_observing); + let (idx, env) = + self.execute_instruction(location, env, continue_observing); (idx.expect("Indexed location must produce a value!").get_u32(), env) - }, + } LocationRule::Mapped { signal_code, indexes } => { let mut acc_env = env; - let io_def = &self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code]; + let io_def = + &self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code]; let map_access = io_def.offset; if indexes.len() > 0 { let mut indexes_values = vec![]; for i in indexes { - let (val, new_env) = self.execute_instruction(i, acc_env, continue_observing); - indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); + let (val, new_env) = + self.execute_instruction(i, acc_env, continue_observing); + indexes_values.push( + val.expect("Mapped location must produce a value!").get_u32(), + ); acc_env = new_env; } let offset = compute_offset(&indexes_values, &io_def.lengths); @@ -266,14 +313,23 @@ impl<'a> BucketInterpreter<'a> { } } - pub fn store_value_in_address<'env>(&self, address: &'env AddressType, location: &'env LocationRule, value: Value, env: Env<'env>, observe: bool) -> Env<'env> { + pub fn store_value_in_address<'env>( + &self, + address: &'env AddressType, + location: &'env LocationRule, + value: Value, + env: Env<'env>, + observe: bool, + ) -> Env<'env> { match address { AddressType::Variable => { let continue_observing = if observe { self.observer.on_location_rule(location, &env) } else { false }; let (idx, env) = match location { - LocationRule::Indexed { location, .. } => self.execute_instruction(location, env, continue_observing), - LocationRule::Mapped { .. } => unreachable!() + LocationRule::Indexed { location, .. } => { + self.execute_instruction(location, env, continue_observing) + } + LocationRule::Mapped { .. } => unreachable!(), }; let idx_value = idx.expect("Indexed location must produce a value!"); @@ -283,13 +339,15 @@ impl<'a> BucketInterpreter<'a> { } else { env } - }, + } AddressType::Signal => { let continue_observing = if observe { self.observer.on_location_rule(location, &env) } else { false }; let (idx, env) = match location { - LocationRule::Indexed { location, .. } => self.execute_instruction(location, env, continue_observing), - LocationRule::Mapped { .. } => unreachable!() + LocationRule::Indexed { location, .. } => { + self.execute_instruction(location, env, continue_observing) + } + LocationRule::Mapped { .. } => unreachable!(), }; let idx_value = idx.expect("Indexed location must produce a value!"); @@ -299,7 +357,7 @@ impl<'a> BucketInterpreter<'a> { } else { env } - }, + } AddressType::SubcmpSignal { cmp_address, input_information, .. } => { let (addr, env) = self.execute_instruction(cmp_address, env, observe); let addr = addr @@ -311,19 +369,28 @@ impl<'a> BucketInterpreter<'a> { if observe { self.observer.on_location_rule(location, &env) } else { false }; let (idx, env, sub_cmp_name) = match location { LocationRule::Indexed { location, template_header } => { - let (idx, env) = self.execute_instruction(location, env, continue_observing); - (idx.expect("Indexed location must produce a value!").get_u32(), env, template_header.clone()) - }, + let (idx, env) = + self.execute_instruction(location, env, continue_observing); + ( + idx.expect("Indexed location must produce a value!").get_u32(), + env, + template_header.clone(), + ) + } LocationRule::Mapped { signal_code, indexes } => { let mut acc_env = env; let name = Some(acc_env.get_subcmp_name(addr).clone()); - let io_def = &self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code]; + let io_def = + &self.io_map[&acc_env.get_subcmp_template_id(addr)][*signal_code]; let map_access = io_def.offset; if indexes.len() > 0 { let mut indexes_values = vec![]; for i in indexes { - let (val, new_env) = self.execute_instruction(i, acc_env, continue_observing); - indexes_values.push(val.expect("Mapped location must produce a value!").get_u32()); + let (val, new_env) = + self.execute_instruction(i, acc_env, continue_observing); + indexes_values.push( + val.expect("Mapped location must produce a value!").get_u32(), + ); acc_env = new_env; } let offset = compute_offset(&indexes_values, &io_def.lengths); @@ -334,22 +401,16 @@ impl<'a> BucketInterpreter<'a> { } }; - let env = env - .set_subcmp_signal(addr, idx, value) - .decrease_subcmp_counter(addr); + let env = env.set_subcmp_signal(addr, idx, value).decrease_subcmp_counter(addr); if let InputInformation::Input { status } = input_information { match status { StatusInput::Last => { - return - env.run_subcmp(addr, &sub_cmp_name.unwrap(), self, observe) - ; + return env.run_subcmp(addr, &sub_cmp_name.unwrap(), self, observe); } StatusInput::Unknown => { if env.subcmp_counter_is_zero(addr) { - return - env.run_subcmp(addr, &sub_cmp_name.unwrap(), self, observe) - ; + return env.run_subcmp(addr, &sub_cmp_name.unwrap(), self, observe); } } _ => {} @@ -360,14 +421,25 @@ impl<'a> BucketInterpreter<'a> { } } - pub fn execute_store_bucket<'env>(&self, bucket: &'env StoreBucket, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_store_bucket<'env>( + &self, + bucket: &'env StoreBucket, + env: Env<'env>, + observe: bool, + ) -> R<'env> { let (src, env) = self.execute_instruction(&bucket.src, env, observe); let src = src.expect("src instruction in StoreBucket must produce a value!"); - let env = self.store_value_in_address(&bucket.dest_address_type, &bucket.dest, src, env, observe); + let env = + self.store_value_in_address(&bucket.dest_address_type, &bucket.dest, src, env, observe); (None, env) } - pub fn execute_compute_bucket<'env>(&self, bucket: &'env ComputeBucket, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_compute_bucket<'env>( + &self, + bucket: &'env ComputeBucket, + env: Env<'env>, + observe: bool, + ) -> R<'env> { let mut stack = vec![]; let mut env = env; for i in &bucket.stack { @@ -384,8 +456,12 @@ impl<'a> BucketInterpreter<'a> { (computed_value, env) } - - pub fn execute_call_bucket<'env>(&self, bucket: &'env CallBucket, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_call_bucket<'env>( + &self, + bucket: &'env CallBucket, + env: Env<'env>, + observe: bool, + ) -> R<'env> { let mut args = vec![]; let mut env = env; for i in &bucket.arguments { @@ -406,13 +482,25 @@ impl<'a> BucketInterpreter<'a> { // Write the result in the destination according to the address type match &bucket.return_info { ReturnType::Intermediate { .. } => (Some(result), env), - ReturnType::Final(final_data) => { - (None, self.store_value_in_address(&final_data.dest_address_type, &final_data.dest, result, env, observe)) - } + ReturnType::Final(final_data) => ( + None, + self.store_value_in_address( + &final_data.dest_address_type, + &final_data.dest, + result, + env, + observe, + ), + ), } } - pub fn execute_branch_bucket<'env>(&self, bucket: &'env BranchBucket, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_branch_bucket<'env>( + &self, + bucket: &'env BranchBucket, + env: Env<'env>, + observe: bool, + ) -> R<'env> { let (value, cond, mut env) = self.execute_conditional_bucket( &bucket.cond, &bucket.if_branch, @@ -427,8 +515,15 @@ impl<'a> BucketInterpreter<'a> { // If cond is None means that the condition instruction evaluates to Unknown // Thus we don't know what branch to take // We take all writes in both branches and set all writes in them as Unknown - let (mut vars, mut signals, mut subcmps) = self.get_write_operations_in_body(&bucket.if_branch, &env); - self.get_write_operations_in_body_rec(&bucket.else_branch, &mut vars, &mut signals, &mut subcmps, &env); + let (mut vars, mut signals, mut subcmps) = + self.get_write_operations_in_body(&bucket.if_branch, &env); + self.get_write_operations_in_body_rec( + &bucket.else_branch, + &mut vars, + &mut signals, + &mut subcmps, + &env, + ); for var in vars { env = env.set_var(var, Unknown); @@ -442,11 +537,21 @@ impl<'a> BucketInterpreter<'a> { (value, env) } - pub fn execute_return_bucket<'env>(&self, bucket: &'env ReturnBucket, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_return_bucket<'env>( + &self, + bucket: &'env ReturnBucket, + env: Env<'env>, + observe: bool, + ) -> R<'env> { self.execute_instruction(&bucket.value, env, observe) } - pub fn execute_assert_bucket<'env>(&self, bucket: &'env AssertBucket, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_assert_bucket<'env>( + &self, + bucket: &'env AssertBucket, + env: Env<'env>, + observe: bool, + ) -> R<'env> { //self.observer.on_assert_bucket(bucket, &env); let (cond, env) = self.execute_instruction(&bucket.evaluate, env, observe); @@ -457,7 +562,12 @@ impl<'a> BucketInterpreter<'a> { (None, env) } - pub fn execute_log_bucket<'env>(&self, bucket: &'env LogBucket, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_log_bucket<'env>( + &self, + bucket: &'env LogBucket, + env: Env<'env>, + observe: bool, + ) -> R<'env> { let mut env = env; for arg in &bucket.argsprint { if let LogBucketArg::LogExp(i) = arg { @@ -482,16 +592,18 @@ impl<'a> BucketInterpreter<'a> { let cond_bool_result = self.value_to_bool(&executed_cond); return match cond_bool_result { - None => { - (None, None, env) - } + None => (None, None, env), Some(true) => { - if cfg!(debug_assertions) { println!("Running then branch"); } + if cfg!(debug_assertions) { + println!("Running then branch"); + } let (ret, env) = self.execute_instructions(&true_branch, env, observe); (ret, Some(true), env) } Some(false) => { - if cfg!(debug_assertions) { println!("Running else branch"); } + if cfg!(debug_assertions) { + println!("Running else branch"); + } let (ret, env) = self.execute_instructions(&false_branch, env, observe); (ret, Some(false), env) } @@ -520,7 +632,12 @@ impl<'a> BucketInterpreter<'a> { /// In the case the condition evaluates to `Unknown` all the memory addresses /// potentially written into in the loop's body are set to `Unknown` to represent /// that we don't know the values after the execution of that loop. - pub fn execute_loop_bucket<'env>(&self, bucket: &'env LoopBucket, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_loop_bucket<'env>( + &self, + bucket: &'env LoopBucket, + env: Env<'env>, + observe: bool, + ) -> R<'env> { //self.observer.on_loop_bucket(bucket, &env); let mut last_value = Some(Unknown); let mut loop_env = env; @@ -542,7 +659,8 @@ impl<'a> BucketInterpreter<'a> { loop_env = new_env; match cond { None => { - let (vars, signals, subcmps) = self.get_write_operations_in_body(&bucket.body, &loop_env); + let (vars, signals, subcmps) = + self.get_write_operations_in_body(&bucket.body, &loop_env); for var in vars { loop_env = loop_env.set_var(var, Unknown); @@ -575,7 +693,8 @@ impl<'a> BucketInterpreter<'a> { let (cmp_id, env) = self.execute_instruction(&bucket.sub_cmp_id, env, observe); let cmp_id = cmp_id.expect("sub_cmp_id subexpression must yield a value!").get_u32(); - let mut env = env.create_subcmp(&bucket.symbol, cmp_id, bucket.number_of_cmp, bucket.template_id); + let mut env = + env.create_subcmp(&bucket.symbol, cmp_id, bucket.number_of_cmp, bucket.template_id); // Run the subcomponents with 0 inputs directly for i in cmp_id..(cmp_id + bucket.number_of_cmp) { if env.subcmp_counter_is_zero(i) { @@ -625,11 +744,21 @@ impl<'a> BucketInterpreter<'a> { self.execute_instructions(&bucket.body, env, observe) } - pub fn execute_nop_bucket<'env>(&self, _bucket: &NopBucket, env: Env<'env>, _observe: bool) -> R<'env> { + pub fn execute_nop_bucket<'env>( + &self, + _bucket: &NopBucket, + env: Env<'env>, + _observe: bool, + ) -> R<'env> { (None, env) } - pub fn execute_instruction<'env>(&self, inst: &'env InstructionPointer, env: Env<'env>, observe: bool) -> R<'env> { + pub fn execute_instruction<'env>( + &self, + inst: &'env InstructionPointer, + env: Env<'env>, + observe: bool, + ) -> R<'env> { let continue_observing = if observe { self.observer.on_instruction(inst, &env) } else { observe }; match inst.as_ref() { diff --git a/circuit_passes/src/bucket_interpreter/operations.rs b/circuit_passes/src/bucket_interpreter/operations.rs index 9f5848823..4be7eb9d4 100644 --- a/circuit_passes/src/bucket_interpreter/operations.rs +++ b/circuit_passes/src/bucket_interpreter/operations.rs @@ -27,13 +27,9 @@ pub fn compute_operation(bucket: &ComputeBucket, stack: &Vec, p: &BigInt) OperatorType::BitOr => resolve_operation(value::bit_or_value, p, &stack), OperatorType::BitAnd => resolve_operation(value::bit_and_value, p, &stack), OperatorType::BitXor => resolve_operation(value::bit_xor_value, p, &stack), - OperatorType::PrefixSub => { - value::prefix_sub(&stack[0], p) - } + OperatorType::PrefixSub => value::prefix_sub(&stack[0], p), OperatorType::BoolNot => KnownU32((!stack[0].to_bool(p)).into()), - OperatorType::Complement => { - value::complement(&stack[0], p) - } + OperatorType::Complement => value::complement(&stack[0], p), OperatorType::ToAddress => value::to_address(&stack[0]), OperatorType::MulAddress => stack.iter().fold(KnownU32(1), value::mul_address), OperatorType::AddAddress => stack.iter().fold(KnownU32(0), value::add_address), @@ -50,7 +46,7 @@ pub fn compute_offset(indexes: &Vec, lengths: &Vec) -> usize { } let mut total_offset = indexes.last().copied().expect("must contain some indexes!"); let mut size_multiplier = lengths.last().copied().expect("must contain some array lengths!"); - for i in (0..lengths.len()-1).rev() { + for i in (0..lengths.len() - 1).rev() { total_offset += indexes[i] * size_multiplier; size_multiplier *= lengths[i]; } @@ -84,11 +80,11 @@ mod test { fn test_increments() { let lengths = vec![5, 7]; for i in 0..lengths[0] { - for j in 0..lengths[1]-1 { + for j in 0..lengths[1] - 1 { let offset = compute_offset(&vec![i, j], &lengths); let next_offset = compute_offset(&vec![i, j + 1], &lengths); assert_eq!(offset + 1, next_offset); } } } -} \ No newline at end of file +} diff --git a/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs b/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs index cb6448fcb..795c89b00 100644 --- a/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs +++ b/circuit_passes/src/passes/deterministic_subcomponent_invocation.rs @@ -95,11 +95,11 @@ impl InterpreterObserver for DeterministicSubCmpInvokePass { fn on_call_bucket(&self, bucket: &CallBucket, env: &Env) -> bool { match &bucket.return_info { - ReturnType::Intermediate {..} => true, + ReturnType::Intermediate { .. } => true, ReturnType::Final(data) => { self.try_resolve_input_status(&data.dest_address_type, env); true - }, + } } } diff --git a/circuit_passes/src/passes/mapped_to_indexed.rs b/circuit_passes/src/passes/mapped_to_indexed.rs index 4a7df6b32..6e29072d0 100644 --- a/circuit_passes/src/passes/mapped_to_indexed.rs +++ b/circuit_passes/src/passes/mapped_to_indexed.rs @@ -19,16 +19,24 @@ pub struct MappedToIndexedPass { impl MappedToIndexedPass { pub fn new(prime: &String) -> Self { - MappedToIndexedPass { memory: PassMemory::new_cell(prime, "".to_string(), Default::default()), replacements: Default::default() } + MappedToIndexedPass { + memory: PassMemory::new_cell(prime, "".to_string(), Default::default()), + replacements: Default::default(), + } } - fn transform_mapped_loc_to_indexed_loc(&self, - cmp_address: &InstructionPointer, indexes: &Vec, signal_code: usize, env: &Env) -> LocationRule { - + fn transform_mapped_loc_to_indexed_loc( + &self, + cmp_address: &InstructionPointer, + indexes: &Vec, + signal_code: usize, + env: &Env, + ) -> LocationRule { let mem = self.memory.borrow(); let interpreter = mem.build_interpreter(self); - let (resolved_addr, acc_env) = interpreter.execute_instruction(cmp_address, env.clone(), false); + let (resolved_addr, acc_env) = + interpreter.execute_instruction(cmp_address, env.clone(), false); let resolved_addr = resolved_addr .expect("cmp_address instruction in SubcmpSignal must produce a value!") @@ -60,24 +68,30 @@ impl MappedToIndexedPass { } } - fn maybe_transform_location_rule(&self, address: &AddressType, location: &LocationRule, env: &Env) -> bool { + fn maybe_transform_location_rule( + &self, + address: &AddressType, + location: &LocationRule, + env: &Env, + ) -> bool { match address { - AddressType::Variable | AddressType::Signal => { - match location { - LocationRule::Indexed { .. } => true, - LocationRule::Mapped { .. } => unreachable!() - } + AddressType::Variable | AddressType::Signal => match location { + LocationRule::Indexed { .. } => true, + LocationRule::Mapped { .. } => unreachable!(), }, - AddressType::SubcmpSignal { cmp_address, .. } => { - match location { - LocationRule::Indexed { .. } => true, - LocationRule::Mapped { indexes, signal_code } => { - let indexed_rule = self.transform_mapped_loc_to_indexed_loc(cmp_address, indexes, *signal_code, env); - self.replacements.borrow_mut().insert(location.clone(), indexed_rule); - true - } + AddressType::SubcmpSignal { cmp_address, .. } => match location { + LocationRule::Indexed { .. } => true, + LocationRule::Mapped { indexes, signal_code } => { + let indexed_rule = self.transform_mapped_loc_to_indexed_loc( + cmp_address, + indexes, + *signal_code, + env, + ); + self.replacements.borrow_mut().insert(location.clone(), indexed_rule); + true } - } + }, } } } @@ -177,7 +191,7 @@ impl CircuitTransformationPass for MappedToIndexedPass { location: self.transform_instruction(location), template_header: template_header.clone(), }, - LocationRule::Mapped { .. } => unreachable!() + LocationRule::Mapped { .. } => unreachable!(), } } diff --git a/code_producers/src/llvm_elements/instructions.rs b/code_producers/src/llvm_elements/instructions.rs index 1496453be..afddc3bca 100644 --- a/code_producers/src/llvm_elements/instructions.rs +++ b/code_producers/src/llvm_elements/instructions.rs @@ -589,10 +589,7 @@ pub fn create_br<'a>(producer: &dyn LLVMIRProducer<'a>, bb: BasicBlock<'a>) -> A producer.llvm().builder.build_unconditional_branch(bb).as_any_value_enum() } -pub fn find_function<'a>( - producer: &dyn LLVMIRProducer<'a>, - name: &str, -) -> FunctionValue<'a> { +pub fn find_function<'a>(producer: &dyn LLVMIRProducer<'a>, name: &str) -> FunctionValue<'a> { producer .llvm() .module @@ -772,7 +769,7 @@ pub fn pointer_cast_with_name<'a>( producer: &dyn LLVMIRProducer<'a>, from: PointerValue<'a>, to: PointerType<'a>, - name: &str + name: &str, ) -> PointerValue<'a> { producer.builder().build_pointer_cast(from, to, name) } @@ -792,4 +789,4 @@ pub fn create_switch<'a>( cases: &[(IntValue<'a>, BasicBlock<'a>)], ) -> InstructionValue<'a> { producer.builder().build_switch(value, else_block, cases) -} \ No newline at end of file +} diff --git a/code_producers/src/llvm_elements/template.rs b/code_producers/src/llvm_elements/template.rs index 10b3946ba..3152d6493 100644 --- a/code_producers/src/llvm_elements/template.rs +++ b/code_producers/src/llvm_elements/template.rs @@ -49,7 +49,10 @@ impl<'a, 'b> LLVMIRProducer<'a> for TemplateLLVMIRProducer<'a, 'b> { } fn get_template_mem_arg(&self, run_fn: FunctionValue<'a>) -> ArrayValue<'a> { - run_fn.get_nth_param(self.template_ctx.signals_arg_offset as u32).unwrap().into_array_value() + run_fn + .get_nth_param(self.template_ctx.signals_arg_offset as u32) + .unwrap() + .into_array_value() } } @@ -125,7 +128,7 @@ impl<'a> TemplateCtx<'a> { pub fn load_subcmp( &self, producer: &dyn LLVMIRProducer<'a>, - id: AnyValueEnum<'a> + id: AnyValueEnum<'a>, ) -> PointerValue<'a> { create_gep(producer, self.subcmps, &[zero(producer), id.into_int_value()]) .into_pointer_value() @@ -137,8 +140,12 @@ impl<'a> TemplateCtx<'a> { producer: &dyn LLVMIRProducer<'a>, id: AnyValueEnum<'a>, ) -> PointerValue<'a> { - let signals = create_gep(producer, self.subcmps, &[zero(producer), id.into_int_value(), zero(producer)]) - .into_pointer_value(); + let signals = create_gep( + producer, + self.subcmps, + &[zero(producer), id.into_int_value(), zero(producer)], + ) + .into_pointer_value(); create_load(producer, signals).into_pointer_value() } @@ -167,10 +174,7 @@ impl<'a> TemplateCtx<'a> { } /// Returns a pointer to the signal array - pub fn get_signal_array( - &self, - _producer: &dyn LLVMIRProducer<'a>, - ) -> AnyValueEnum<'a> { + pub fn get_signal_array(&self, _producer: &dyn LLVMIRProducer<'a>) -> AnyValueEnum<'a> { let signals = self.current_function.get_nth_param(self.signals_arg_offset as u32).unwrap(); signals.into_pointer_value().into() } @@ -186,10 +190,7 @@ impl<'a> BodyCtx<'a> for TemplateCtx<'a> { create_gep(producer, self.stack, &[zero(producer), index]) } - fn get_variable_array( - &self, - _producer: &dyn LLVMIRProducer<'a>, - ) -> AnyValueEnum<'a> { + fn get_variable_array(&self, _producer: &dyn LLVMIRProducer<'a>) -> AnyValueEnum<'a> { self.stack.into() } } diff --git a/compiler/src/intermediate_representation/block_bucket.rs b/compiler/src/intermediate_representation/block_bucket.rs index 0069982c8..12a1f5623 100644 --- a/compiler/src/intermediate_representation/block_bucket.rs +++ b/compiler/src/intermediate_representation/block_bucket.rs @@ -1,5 +1,7 @@ use code_producers::llvm_elements::{LLVMInstruction, LLVMIRProducer}; -use crate::intermediate_representation::{BucketId, Instruction, InstructionList, InstructionPointer, new_id, SExp, ToSExp, UpdateId}; +use crate::intermediate_representation::{ + BucketId, Instruction, InstructionList, InstructionPointer, new_id, SExp, ToSExp, UpdateId, +}; use crate::intermediate_representation::ir_interface::{Allocate, IntoInstruction, ObtainMeta}; use crate::translating_traits::WriteLLVMIR; @@ -10,7 +12,7 @@ pub struct BlockBucket { pub line: usize, pub message_id: usize, pub body: InstructionList, - pub n_iters: usize + pub n_iters: usize, } impl IntoInstruction for BlockBucket { @@ -46,7 +48,10 @@ impl ToString for BlockBucket { body = format!("{} - {};\n", body, i.to_string()); } body = format!("{}]", body); - format!("BLOCK(line:{},template_id:{},n_iterations:{},body:{})", line, template_id, self.n_iters, body) + format!( + "BLOCK(line:{},template_id:{},n_iterations:{},body:{})", + line, template_id, self.n_iters, body + ) } } @@ -57,7 +62,7 @@ impl ToSExp for BlockBucket { SExp::Atom(format!("line:{}", self.line)), SExp::Atom(format!("template_id:{}", self.message_id)), SExp::Atom(format!("n_iterations:{}", self.n_iters)), - SExp::List(self.body.iter().map(|i| i.to_sexp()).collect()) + SExp::List(self.body.iter().map(|i| i.to_sexp()).collect()), ]) } } @@ -72,7 +77,10 @@ impl UpdateId for BlockBucket { } impl WriteLLVMIR for BlockBucket { - fn produce_llvm_ir<'a, 'b>(&self, producer: &'b dyn LLVMIRProducer<'a>) -> Option> { + fn produce_llvm_ir<'a, 'b>( + &self, + producer: &'b dyn LLVMIRProducer<'a>, + ) -> Option> { Self::manage_debug_loc_from_curr(producer, self); let mut last = None; @@ -81,4 +89,4 @@ impl WriteLLVMIR for BlockBucket { } last } -} \ No newline at end of file +} diff --git a/compiler/src/intermediate_representation/constraint_bucket.rs b/compiler/src/intermediate_representation/constraint_bucket.rs index 74a9bc47d..ddf04fe75 100644 --- a/compiler/src/intermediate_representation/constraint_bucket.rs +++ b/compiler/src/intermediate_representation/constraint_bucket.rs @@ -1,5 +1,7 @@ use code_producers::c_elements::CProducer; -use code_producers::llvm_elements::{LLVMInstruction, new_constraint, to_basic_metadata_enum, LLVMIRProducer}; +use code_producers::llvm_elements::{ + LLVMInstruction, new_constraint, to_basic_metadata_enum, LLVMIRProducer, +}; use code_producers::llvm_elements::instructions::{create_call, create_load, get_instruction_arg}; use code_producers::llvm_elements::stdlib::{CONSTRAINT_VALUE_FN_NAME, CONSTRAINT_VALUES_FN_NAME}; use code_producers::wasm_elements::WASMProducer; @@ -10,21 +12,21 @@ use crate::translating_traits::{WriteC, WriteLLVMIR, WriteWasm}; #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum ConstraintBucket { Substitution(InstructionPointer), - Equality(InstructionPointer) + Equality(InstructionPointer), } impl ConstraintBucket { pub fn unwrap(&self) -> &InstructionPointer { match self { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i + ConstraintBucket::Equality(i) => i, } } pub fn unwrap_mut(&mut self) -> &mut InstructionPointer { match self { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i + ConstraintBucket::Equality(i) => i, } } } @@ -45,20 +47,23 @@ impl ObtainMeta for ConstraintBucket { fn get_source_file_id(&self) -> &Option { match self { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i - }.get_source_file_id() + ConstraintBucket::Equality(i) => i, + } + .get_source_file_id() } fn get_line(&self) -> usize { match self { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i - }.get_line() + ConstraintBucket::Equality(i) => i, + } + .get_line() } fn get_message_id(&self) -> usize { match self { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i - }.get_message_id() + ConstraintBucket::Equality(i) => i, + } + .get_message_id() } } @@ -68,18 +73,16 @@ impl ToString for ConstraintBucket { "CONSTRAINT:{}", match self { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i - }.to_string() + ConstraintBucket::Equality(i) => i, + } + .to_string() ) } } impl ToSExp for ConstraintBucket { fn to_sexp(&self) -> SExp { - SExp::List(vec![ - SExp::Atom("CONSTRAINT".to_string()), - self.unwrap().to_sexp(), - ]) + SExp::List(vec![SExp::Atom("CONSTRAINT".to_string()), self.unwrap().to_sexp()]) } } @@ -90,14 +93,19 @@ impl UpdateId for ConstraintBucket { } impl WriteLLVMIR for ConstraintBucket { - fn produce_llvm_ir<'a, 'b>(&self, producer: &'b dyn LLVMIRProducer<'a>) -> Option> { + fn produce_llvm_ir<'a, 'b>( + &self, + producer: &'b dyn LLVMIRProducer<'a>, + ) -> Option> { Self::manage_debug_loc_from_curr(producer, self); // TODO: Create the constraint call let prev = match self { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i - }.produce_llvm_ir(producer).expect("A constrained instruction MUST produce a value!"); + ConstraintBucket::Equality(i) => i, + } + .produce_llvm_ir(producer) + .expect("A constrained instruction MUST produce a value!"); const STORE_SRC_IDX: u32 = 1; const STORE_DST_IDX: u32 = 0; @@ -107,20 +115,27 @@ impl WriteLLVMIR for ConstraintBucket { ConstraintBucket::Substitution(_) => { let lhs = get_instruction_arg(prev.into_instruction_value(), STORE_DST_IDX); let rhs_ptr = get_instruction_arg(prev.into_instruction_value(), STORE_SRC_IDX); - let rhs = create_load(producer,rhs_ptr.into_pointer_value()); + let rhs = create_load(producer, rhs_ptr.into_pointer_value()); let constr = new_constraint(producer); - let call = create_call(producer,CONSTRAINT_VALUES_FN_NAME, &[ - to_basic_metadata_enum(lhs), - to_basic_metadata_enum(rhs), - to_basic_metadata_enum(constr)]); + let call = create_call( + producer, + CONSTRAINT_VALUES_FN_NAME, + &[ + to_basic_metadata_enum(lhs), + to_basic_metadata_enum(rhs), + to_basic_metadata_enum(constr), + ], + ); Some(call) } ConstraintBucket::Equality(_) => { let bool = get_instruction_arg(prev.into_instruction_value(), ASSERT_IDX); let constr = new_constraint(producer); - let call = create_call(producer, CONSTRAINT_VALUE_FN_NAME, &[ - to_basic_metadata_enum(bool), - to_basic_metadata_enum(constr)]); + let call = create_call( + producer, + CONSTRAINT_VALUE_FN_NAME, + &[to_basic_metadata_enum(bool), to_basic_metadata_enum(constr)], + ); Some(call) } } @@ -131,8 +146,9 @@ impl WriteWasm for ConstraintBucket { fn produce_wasm(&self, producer: &WASMProducer) -> Vec { match self { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i - }.produce_wasm(producer) + ConstraintBucket::Equality(i) => i, + } + .produce_wasm(producer) } } @@ -140,7 +156,8 @@ impl WriteC for ConstraintBucket { fn produce_c(&self, producer: &CProducer, is_parallel: Option) -> (Vec, String) { match self { ConstraintBucket::Substitution(i) => i, - ConstraintBucket::Equality(i) => i - }.produce_c(producer, is_parallel) + ConstraintBucket::Equality(i) => i, + } + .produce_c(producer, is_parallel) } -} \ No newline at end of file +} diff --git a/compiler/src/intermediate_representation/nop_bucket.rs b/compiler/src/intermediate_representation/nop_bucket.rs index 3eb92a935..1b129f6ed 100644 --- a/compiler/src/intermediate_representation/nop_bucket.rs +++ b/compiler/src/intermediate_representation/nop_bucket.rs @@ -1,5 +1,7 @@ use code_producers::llvm_elements::{LLVMInstruction, LLVMIRProducer}; -use crate::intermediate_representation::{BucketId, Instruction, InstructionPointer, new_id, SExp, ToSExp, UpdateId}; +use crate::intermediate_representation::{ + BucketId, Instruction, InstructionPointer, new_id, SExp, ToSExp, UpdateId, +}; use crate::intermediate_representation::ir_interface::{Allocate, IntoInstruction, ObtainMeta}; use crate::translating_traits::WriteLLVMIR; @@ -51,7 +53,10 @@ impl UpdateId for NopBucket { } impl WriteLLVMIR for NopBucket { - fn produce_llvm_ir<'a, 'b>(&self, _producer: &'b dyn LLVMIRProducer<'a>) -> Option> { + fn produce_llvm_ir<'a, 'b>( + &self, + _producer: &'b dyn LLVMIRProducer<'a>, + ) -> Option> { None } -} \ No newline at end of file +} diff --git a/parser/src/errors.rs b/parser/src/errors.rs index 5af6dbd9b..cf81f3b47 100644 --- a/parser/src/errors.rs +++ b/parser/src/errors.rs @@ -60,7 +60,7 @@ impl MultipleMainError { } } -pub struct CompilerVersionError{ +pub struct CompilerVersionError { pub path: String, pub required_version: Version, pub version: Version, @@ -74,81 +74,79 @@ impl CompilerVersionError { } } - - -pub struct NoCompilerVersionWarning{ +pub struct NoCompilerVersionWarning { pub path: String, pub version: Version, } impl NoCompilerVersionWarning { pub fn produce_report(error: Self) -> Report { Report::warning( - format!("File {} does not include pragma version. Assuming pragma version {:?}", error.path, error.version), + format!( + "File {} does not include pragma version. Assuming pragma version {:?}", + error.path, error.version + ), ReportCode::NoCompilerVersionWarning, ) } } -pub struct AnonymousCompError{ +pub struct AnonymousCompError { pub location: FileLocation, - pub msg : String + pub msg: String, } impl AnonymousCompError { - pub fn produce_report( error : Self) -> Report { - Report::error( - format!("{}", error.msg), - ReportCode::AnonymousCompError, - ) + pub fn produce_report(error: Self) -> Report { + Report::error(format!("{}", error.msg), ReportCode::AnonymousCompError) } - pub fn anonymous_inside_condition_error(meta : Meta) -> Report { - let error = AnonymousCompError {msg: "An anonymous component cannot be used inside a condition ".to_string(), location : meta.location.clone()}; - let mut report = AnonymousCompError::produce_report(error); - let file_id = meta.get_file_id().clone(); - report.add_primary( - meta.location, - file_id, - "This is an anonymous component used inside a condition".to_string(), - ); - report + pub fn anonymous_inside_condition_error(meta: Meta) -> Report { + let error = AnonymousCompError { + msg: "An anonymous component cannot be used inside a condition ".to_string(), + location: meta.location.clone(), + }; + let mut report = AnonymousCompError::produce_report(error); + let file_id = meta.get_file_id().clone(); + report.add_primary( + meta.location, + file_id, + "This is an anonymous component used inside a condition".to_string(), + ); + report } - - pub fn anonymous_general_error(meta : Meta, msg : String) -> Report { - let error = AnonymousCompError {msg, location : meta.location.clone()}; - let mut report = AnonymousCompError::produce_report(error); - let file_id = meta.get_file_id().clone(); - report.add_primary( - meta.location, - file_id, - "This is the anonymous component whose use is not allowed".to_string(), - ); - report + + pub fn anonymous_general_error(meta: Meta, msg: String) -> Report { + let error = AnonymousCompError { msg, location: meta.location.clone() }; + let mut report = AnonymousCompError::produce_report(error); + let file_id = meta.get_file_id().clone(); + report.add_primary( + meta.location, + file_id, + "This is the anonymous component whose use is not allowed".to_string(), + ); + report } } -pub struct TupleError{ +pub struct TupleError { pub location: FileLocation, - pub msg : String + pub msg: String, } impl TupleError { - pub fn produce_report( error : Self) -> Report { - Report::error( - format!("{}", error.msg), - ReportCode::TupleError, - ) + pub fn produce_report(error: Self) -> Report { + Report::error(format!("{}", error.msg), ReportCode::TupleError) } - pub fn tuple_general_error(meta : Meta, msg : String) -> Report { - let error = TupleError {msg, location : meta.location.clone()}; - let mut report = TupleError::produce_report(error); - let file_id = meta.get_file_id().clone(); - report.add_primary( - meta.location, - file_id, - "This is the tuple whose use is not allowed".to_string(), - ); - report + pub fn tuple_general_error(meta: Meta, msg: String) -> Report { + let error = TupleError { msg, location: meta.location.clone() }; + let mut report = TupleError::produce_report(error); + let file_id = meta.get_file_id().clone(); + report.add_primary( + meta.location, + file_id, + "This is the tuple whose use is not allowed".to_string(), + ); + report } -} \ No newline at end of file +} From 2a69d6a6a0aff194cbde3c9a4641f092362eb7db Mon Sep 17 00:00:00 2001 From: Timothy Hoffman <4001421+tim-hoffman@users.noreply.github.com> Date: Sat, 26 Aug 2023 14:39:55 -0500 Subject: [PATCH 12/12] Add regression tests for loop unrolling (#49) record current status before making changes to unrolling --- circom/tests/loops/fib_input.circom | 16 ++++- circom/tests/loops/fib_template.circom | 22 +++++- circom/tests/loops/for_known.circom | 20 +++++- circom/tests/loops/for_unknown.circom | 14 +++- circom/tests/loops/for_unknown_index.circom | 14 +++- circom/tests/loops/inner_loops.circom | 71 ++++++++++++++++++- circom/tests/loops/inner_loops2.circom | 2 +- circom/tests/loops/inner_loops3.circom | 2 +- circom/tests/loops/inner_loops4.circom | 2 +- circom/tests/loops/known_function.circom | 48 +++++++++++++ circom/tests/loops/known_signal_value.circom | 39 ++++++++++ .../loops/unknown_local_array_index.circom | 14 +++- .../tests/loops/unknown_loop_component.circom | 20 +++++- circom/tests/loops/unknown_loop_index.circom | 38 +++++++++- circom/tests/loops/unknown_loop_oob.circom | 20 +++++- 15 files changed, 316 insertions(+), 26 deletions(-) create mode 100644 circom/tests/loops/known_function.circom create mode 100644 circom/tests/loops/known_signal_value.circom diff --git a/circom/tests/loops/fib_input.circom b/circom/tests/loops/fib_input.circom index ac8362253..6b664f2e6 100644 --- a/circom/tests/loops/fib_input.circom +++ b/circom/tests/loops/fib_input.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template Fibonacci() { signal input nth_fib; @@ -11,7 +11,7 @@ template Fibonacci() { var next = 0; var counter = nth_fib; - while (counter > 2) { + while (counter > 2) { // unknown iteration count next = a + b; a = b; b = next; @@ -22,4 +22,14 @@ template Fibonacci() { out <-- (nth_fib == 0) ? 0 : (nth_fib == 1 ? 1 : a + b); } -component main = Fibonacci(); \ No newline at end of file +component main = Fibonacci(); + +//// Use the block labels to check that the loop is NOT unrolled +//CHECK-LABEL: define void @Fibonacci_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: loop.cond{{.*}}: +//CHECK: loop.body{{.*}}: +//CHECK: loop.end{{.*}}: +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: } diff --git a/circom/tests/loops/fib_template.circom b/circom/tests/loops/fib_template.circom index e6dc16a7b..c3ee4e755 100644 --- a/circom/tests/loops/fib_template.circom +++ b/circom/tests/loops/fib_template.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template FibonacciTmpl(N) { signal output out; @@ -10,7 +10,7 @@ template FibonacciTmpl(N) { var next = 0; var counter = N; - while (counter > 2) { + while (counter > 2) { // known iteration count next = a + b; a = b; b = next; @@ -27,4 +27,20 @@ template FibonacciTmpl(N) { } } -component main = FibonacciTmpl(5); \ No newline at end of file +component main = FibonacciTmpl(5); + +//CHECK-LABEL: define void @FibonacciTmpl_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//// Use the block labels to check that the loop is unrolled +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//CHECK: unrolled_loop{{.*}}: +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//// Check that final value stored to 'out' is computed correctly via unrolling +//CHECK: store{{[0-9]+}}: +//CHECK: %[[T:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 0 +//CHECK: store i256 5, i256* %{{.*}}[[T]], align 4 +//CHECK: } diff --git a/circom/tests/loops/for_known.circom b/circom/tests/loops/for_known.circom index 3508ba4ae..77b7f14ae 100644 --- a/circom/tests/loops/for_known.circom +++ b/circom/tests/loops/for_known.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template ForKnown(N) { signal output out; @@ -13,4 +13,20 @@ template ForKnown(N) { out <-- acc; } -component main = ForKnown(10); \ No newline at end of file +component main = ForKnown(10); + +//CHECK-LABEL: define void @ForKnown_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//// Use the block labels to check that the loop is unrolled +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//CHECK: unrolled_loop{{.*}}: +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//// Check that final value stored to 'out' is computed correctly via unrolling +//CHECK: store{{[0-9]+}}: +//CHECK: %[[T:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 0 +//CHECK: store i256 55, i256* %{{.*}}[[T]], align 4 +//CHECK: } diff --git a/circom/tests/loops/for_unknown.circom b/circom/tests/loops/for_unknown.circom index a93572610..888061553 100644 --- a/circom/tests/loops/for_unknown.circom +++ b/circom/tests/loops/for_unknown.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template ForUnknown() { signal input in; @@ -14,4 +14,14 @@ template ForUnknown() { out <-- acc; } -component main = ForUnknown(); \ No newline at end of file +component main = ForUnknown(); + +//// Use the block labels to check that the loop is NOT unrolled +//CHECK-LABEL: define void @ForUnknown_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: loop.cond{{.*}}: +//CHECK: loop.body{{.*}}: +//CHECK: loop.end{{.*}}: +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: } diff --git a/circom/tests/loops/for_unknown_index.circom b/circom/tests/loops/for_unknown_index.circom index 495e4b1ca..87bde3fbb 100644 --- a/circom/tests/loops/for_unknown_index.circom +++ b/circom/tests/loops/for_unknown_index.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template ForUnknownIndex() { signal input in; @@ -17,4 +17,14 @@ template ForUnknownIndex() { out <-- arr[acc]; } -component main = ForUnknownIndex(); \ No newline at end of file +component main = ForUnknownIndex(); + +//// Use the block labels to check that the loop is NOT unrolled +//CHECK-LABEL: define void @ForUnknownIndex_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: loop.cond{{.*}}: +//CHECK: loop.body{{.*}}: +//CHECK: loop.end{{.*}}: +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: } diff --git a/circom/tests/loops/inner_loops.circom b/circom/tests/loops/inner_loops.circom index d1b80e98f..7205dfb5f 100644 --- a/circom/tests/loops/inner_loops.circom +++ b/circom/tests/loops/inner_loops.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template InnerLoops(n) { signal input a[n]; @@ -8,9 +8,74 @@ template InnerLoops(n) { for (var i = 0; i < n; i++) { for (var j = 0; j <= i; j++) { - b[i] = a[i - j]; + b[i] += a[i - j]; } } } -component main = InnerLoops(2); \ No newline at end of file +component main = InnerLoops(2); +// +//ARG = { a[0], a[1] } +//lvars = { n, b[0], b[1], i, j } +//unrolled code: +// b[0] = b[0] + a[0 - 0 = 0]; +// b[1] = b[1] + a[1 - 0 = 1]; +// b[1] = b[1] + a[1 - 1 = 0]; +// +// +//CHECK-LABEL: define void @InnerLoops_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//// Use the block labels to check that the loop is unrolled and check the unrolled body +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//CHECK: unrolled_loop{{.*}}: +// // j = 0 +//CHECK-NEXT: %[[T01:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 4 +//CHECK-NEXT: store i256 0, i256* %{{.*}}[[T01]], align 4 +// // b[0] = b[0] + a[0] +//CHECK-NEXT: %[[T02:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 1 +//CHECK-NEXT: %[[T03:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T02]], align 4 +//CHECK-NEXT: %[[T04:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 0 +//CHECK-NEXT: %[[T05:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T04]], align 4 +//CHECK-NEXT: %[[T06:[[:alnum:]_.]+]] = call i256 @fr_add(i256 %{{.*}}[[T03]], i256 %{{.*}}[[T05]]) +//CHECK-NEXT: %[[T07:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 1 +//CHECK-NEXT: store i256 %{{.*}}[[T06]], i256* %{{.*}}[[T07]], align 4 +// // j = 1 +//CHECK-NEXT: %[[T08:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 4 +//CHECK-NEXT: store i256 1, i256* %{{.*}}[[T08]], align 4 +// // i = 1 +//CHECK-NEXT: %[[T09:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 3 +//CHECK-NEXT: store i256 1, i256* %{{.*}}[[T09]], align 4 +// // j = 0 +//CHECK-NEXT: %[[T10:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 4 +//CHECK-NEXT: store i256 0, i256* %{{.*}}[[T10]], align 4 +// // b[1] = b[1] + a[1] +//CHECK-NEXT: %[[T11:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 2 +//CHECK-NEXT: %[[T12:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T11]], align 4 +//CHECK-NEXT: %[[T13:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 1 +//CHECK-NEXT: %[[T14:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T13]], align 4 +//CHECK-NEXT: %[[T15:[[:alnum:]_.]+]] = call i256 @fr_add(i256 %{{.*}}[[T12]], i256 %{{.*}}[[T14]]) +//CHECK-NEXT: %[[T16:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 2 +//CHECK-NEXT: store i256 %{{.*}}[[T15]], i256* %{{.*}}[[T16]], align 4 +// // j = 1 +//CHECK-NEXT: %[[T17:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 4 +//CHECK-NEXT: store i256 1, i256* %{{.*}}[[T17]], align 4 +// // b[1] = b[1] + a[0] +//CHECK-NEXT: %[[T18:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 2 +//CHECK-NEXT: %[[T19:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T18]], align 4 +//CHECK-NEXT: %[[T20:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 0 +//CHECK-NEXT: %[[T21:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T20]], align 4 +//CHECK-NEXT: %[[T22:[[:alnum:]_.]+]] = call i256 @fr_add(i256 %{{.*}}[[T19]], i256 %{{.*}}[[T21]]) +//CHECK-NEXT: %[[T23:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 2 +//CHECK-NEXT: store i256 %{{.*}}[[T22]], i256* %{{.*}}[[T23]], align 4 +// // j = 2 +//CHECK-NEXT: %[[T24:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 4 +//CHECK-NEXT: store i256 2, i256* %{{.*}}[[T24]], align 4 +// // i = 2 +//CHECK-NEXT: %[[T25:[[:alnum:]_.]+]] = getelementptr [5 x i256], [5 x i256]* %lvars, i32 0, i32 3 +//CHECK-NEXT: store i256 2, i256* %{{.*}}[[T25]], align 4 +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//CHECK: } diff --git a/circom/tests/loops/inner_loops2.circom b/circom/tests/loops/inner_loops2.circom index c9f5fecc6..fe405a82f 100644 --- a/circom/tests/loops/inner_loops2.circom +++ b/circom/tests/loops/inner_loops2.circom @@ -32,4 +32,4 @@ template InnerLoops(n) { i++; // 5 } -component main = InnerLoops(5); \ No newline at end of file +component main = InnerLoops(5); diff --git a/circom/tests/loops/inner_loops3.circom b/circom/tests/loops/inner_loops3.circom index bf735f369..9c193f329 100644 --- a/circom/tests/loops/inner_loops3.circom +++ b/circom/tests/loops/inner_loops3.circom @@ -23,4 +23,4 @@ template InnerLoops(n) { } } -component main = InnerLoops(5); \ No newline at end of file +component main = InnerLoops(5); diff --git a/circom/tests/loops/inner_loops4.circom b/circom/tests/loops/inner_loops4.circom index 0f636e23f..a85aa859b 100644 --- a/circom/tests/loops/inner_loops4.circom +++ b/circom/tests/loops/inner_loops4.circom @@ -13,4 +13,4 @@ template InnerLoops(n) { } } -component main = InnerLoops(2); \ No newline at end of file +component main = InnerLoops(2); diff --git a/circom/tests/loops/known_function.circom b/circom/tests/loops/known_function.circom new file mode 100644 index 000000000..65b837850 --- /dev/null +++ b/circom/tests/loops/known_function.circom @@ -0,0 +1,48 @@ +pragma circom 2.0.0; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s + +function funWithLoop(n) { + var acc = 0; + for (var i = 1; i <= n; i++) { + acc += i; + } + return acc; +} + +template KnownFunctionArgs() { + signal output out[3]; + + out[0] <-- funWithLoop(4); // 0 + 1 + 2 + 3 + 4 = 10 + out[1] <-- funWithLoop(5); // 0 + 1 + 2 + 3 + 4 + 5 = 15 + + var acc = 1; + for (var i = 2; i <= funWithLoop(3); i++) { + acc *= i; + } + out[2] <-- acc; // 1 * 2 * 3 * 4 * 5 * 6 = 720 +} + +component main = KnownFunctionArgs(); + +//CHECK-LABEL: define void @KnownFunctionArgs_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//// Check storing initial constant values to 'out' +//CHECK: store{{[0-9]+}}: +//CHECK: %[[T1:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 0 +//CHECK: store i256 10, i256* %{{.*}}[[T1]], align 4 +//CHECK: store{{[0-9]+}}: +//CHECK: %[[T2:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 1 +//CHECK: store i256 15, i256* %{{.*}}[[T2]], align 4 +//// Use the block labels to check that the loop is unrolled +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//CHECK: unrolled_loop{{.*}}: +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//// Check that final value stored to 'out' is computed correctly via unrolling +//CHECK: store{{[0-9]+}}: +//CHECK: %[[T3:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 2 +//CHECK: store i256 720, i256* %{{.*}}[[T3]], align 4 diff --git a/circom/tests/loops/known_signal_value.circom b/circom/tests/loops/known_signal_value.circom new file mode 100644 index 000000000..6038f1785 --- /dev/null +++ b/circom/tests/loops/known_signal_value.circom @@ -0,0 +1,39 @@ +pragma circom 2.0.0; +// REQUIRES: circom +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s + +template accumulate() { + signal input i; + signal output o; + var r = 0; + while (r < i) { + r++; + } + o <-- r; +} + +template KnownLoopViaSignal() { + signal output y; + + component a = accumulate(); + a.i <-- 5; + y <-- a.o; +} + +component main = KnownLoopViaSignal(); + +//// Use the block labels to check that the loop is NOT unrolled +//CHECK-LABEL: define void @accumulate_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: loop.cond{{.*}}: +//CHECK: loop.body{{.*}}: +//CHECK: loop.end{{.*}}: +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: } + +//// Use the block labels to check that no loop related blocks are present +//CHECK-LABEL: define void @KnownLoopViaSignal_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: {{.*}}loop{{.*}}: +//CHECK: } diff --git a/circom/tests/loops/unknown_local_array_index.circom b/circom/tests/loops/unknown_local_array_index.circom index fae97a25b..77b690851 100644 --- a/circom/tests/loops/unknown_local_array_index.circom +++ b/circom/tests/loops/unknown_local_array_index.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template ForUnknownIndex() { signal input in; @@ -20,4 +20,14 @@ template ForUnknownIndex() { out <-- arr2[acc % 10]; } -component main = ForUnknownIndex(); \ No newline at end of file +component main = ForUnknownIndex(); + +//// Use the block labels to check that the loop is NOT unrolled +//CHECK-LABEL: define void @ForUnknownIndex_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: loop.cond{{.*}}: +//CHECK: loop.body{{.*}}: +//CHECK: loop.end{{.*}}: +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: } diff --git a/circom/tests/loops/unknown_loop_component.circom b/circom/tests/loops/unknown_loop_component.circom index 6dbbe60f8..e20626b59 100644 --- a/circom/tests/loops/unknown_loop_component.circom +++ b/circom/tests/loops/unknown_loop_component.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template nbits() { signal input in; @@ -23,4 +23,20 @@ template UnknownLoopComponent() { bits <-- nb.out; } -component main = UnknownLoopComponent(); \ No newline at end of file +component main = UnknownLoopComponent(); + +//// Use the block labels to check that the loop is NOT unrolled +//CHECK-LABEL: define void @nbits_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: loop.cond{{.*}}: +//CHECK: loop.body{{.*}}: +//CHECK: loop.end{{.*}}: +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: } + +//// Use the block labels to check that no loop related blocks are present +//CHECK-LABEL: define void @UnknownLoopComponent_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: {{.*}}loop{{.*}}: +//CHECK: } diff --git a/circom/tests/loops/unknown_loop_index.circom b/circom/tests/loops/unknown_loop_index.circom index 357841e32..b9656b80f 100644 --- a/circom/tests/loops/unknown_loop_index.circom +++ b/circom/tests/loops/unknown_loop_index.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template Num2Bits(n) { signal input in; @@ -64,4 +64,38 @@ template UnknownLoopIndex(n) { out <-- choices[c.out]; } -component main = UnknownLoopIndex(100); \ No newline at end of file +component main = UnknownLoopIndex(100); + +//// Use the block labels to check that the loop is unrolled +//CHECK-LABEL: define void @Num2Bits_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//CHECK: unrolled_loop{{.*}}: +//CHECK-NOT: loop.cond{{.*}}: +//CHECK-NOT: loop.body{{.*}}: +//CHECK-NOT: loop.end{{.*}}: +//CHECK: } + +//// Use the block labels to check that no loop related blocks are present +//CHECK-LABEL: define void @LessThan_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: {{.*}}loop{{.*}}: +//CHECK: } + +//// Use the block labels to check that the loop is NOT unrolled +//CHECK-LABEL: define void @CountDown_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: loop.cond{{.*}}: +//CHECK: loop.body{{.*}}: +//CHECK: loop.end{{.*}}: +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: } + +//// Use the block labels to check that no loop related blocks are present +//CHECK-LABEL: define void @UnknownLoopIndex_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: {{.*}}loop{{.*}}: +//CHECK: } diff --git a/circom/tests/loops/unknown_loop_oob.circom b/circom/tests/loops/unknown_loop_oob.circom index 5fed384d3..d167fb514 100644 --- a/circom/tests/loops/unknown_loop_oob.circom +++ b/circom/tests/loops/unknown_loop_oob.circom @@ -1,6 +1,6 @@ pragma circom 2.0.0; // REQUIRES: circom -// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s +// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s template accumulate() { signal input i; @@ -22,4 +22,20 @@ template UnknownLoopOOB() { y <-- n[a.o]; } -component main = UnknownLoopOOB(); \ No newline at end of file +component main = UnknownLoopOOB(); + +//// Use the block labels to check that the loop is NOT unrolled +//CHECK-LABEL: define void @accumulate_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: loop.cond{{.*}}: +//CHECK: loop.body{{.*}}: +//CHECK: loop.end{{.*}}: +//CHECK-NOT: unrolled_loop{{.*}}: +//CHECK: } + +//// Use the block labels to check that no loop related blocks are present +//CHECK-LABEL: define void @UnknownLoopOOB_{{[0-9]+}}_run +//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]]) +//CHECK-NOT: {{.*}}loop{{.*}}: +//CHECK: }