From b1f85b48233d96d3c2ac11c913439c6cedc8489b Mon Sep 17 00:00:00 2001 From: Ian Glen Neal Date: Tue, 15 Aug 2023 16:41:53 -0400 Subject: [PATCH 1/3] Add minimized test case --- circom/tests/subcmps/subcmps2.circom | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) 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..d287e3848 --- /dev/null +++ b/circom/tests/subcmps/subcmps2.circom @@ -0,0 +1,33 @@ +pragma circom 2.0.6; + +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(); \ No newline at end of file From 58979a63b5fed9e66c6232a43aadb55fd1611070 Mon Sep 17 00:00:00 2001 From: Ian Glen Neal Date: Wed, 16 Aug 2023 15:08:34 -0400 Subject: [PATCH 2/3] Add InputStatus resolution for final return data --- circom/tests/subcmps/subcmps2.circom | 7 +++ .../deterministic_subcomponent_invocation.rs | 52 +++++++++++-------- .../store_bucket.rs | 2 +- 3 files changed, 39 insertions(+), 22 deletions(-) diff --git a/circom/tests/subcmps/subcmps2.circom b/circom/tests/subcmps/subcmps2.circom index d287e3848..2165b3079 100644 --- a/circom/tests/subcmps/subcmps2.circom +++ b/circom/tests/subcmps/subcmps2.circom @@ -1,4 +1,6 @@ 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]; @@ -25,6 +27,11 @@ template Caller() { for (var i = 0; i < 4; i++) { s.inp[i] <== nop(inp[i]); + //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]] } outp <== s.outp; 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 a4d42622242a19408551202c5493ef4b2c24b262 Mon Sep 17 00:00:00 2001 From: Ian Glen Neal Date: Thu, 17 Aug 2023 13:06:30 -0400 Subject: [PATCH 3/3] Add CHECK-LABEL --- circom/tests/subcmps/subcmps2.circom | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/circom/tests/subcmps/subcmps2.circom b/circom/tests/subcmps/subcmps2.circom index 2165b3079..6f1668e7e 100644 --- a/circom/tests/subcmps/subcmps2.circom +++ b/circom/tests/subcmps/subcmps2.circom @@ -27,14 +27,17 @@ template Caller() { for (var i = 0; i < 4; i++) { s.inp[i] <== nop(inp[i]); - //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]] } outp <== s.outp; } -component main = Caller(); \ No newline at end of file +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]]