Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VAN-545] extract loop body to separate function before unrolling #52

Merged
merged 43 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
930af13
make PassMemory mutability more fine-grained
tim-hoffman Aug 22, 2023
a5946dd
code cleanup
tim-hoffman Aug 22, 2023
0bd386e
implement loop body extraction for very basic case
tim-hoffman Aug 23, 2023
a4cec75
code cleanup
tim-hoffman Aug 23, 2023
da4d12b
documentation
tim-hoffman Aug 23, 2023
c2a188f
More cleanup from the PassMemory changes
tim-hoffman Aug 24, 2023
c83d843
complete extraction for simple cases
tim-hoffman Sep 6, 2023
539f6ba
[VAN-609] inline the array indexing/identity functions
tim-hoffman Sep 6, 2023
fb638f5
fix scalar return source functions
tim-hoffman Sep 6, 2023
bbf2658
fix tests other than nested loops and subcomps
tim-hoffman Sep 7, 2023
609d261
one more test fix
tim-hoffman Sep 7, 2023
6da25a1
fix loop_unroll unit test
tim-hoffman Sep 7, 2023
d6621d3
temporarily XFAIL subcomp and nested loop tests
tim-hoffman Sep 7, 2023
ad2ee2f
fix/update some tests
tim-hoffman Sep 8, 2023
0d93f52
add bool to dis/enable loop body extraction
tim-hoffman Sep 11, 2023
60de11a
update/add more tests
tim-hoffman Sep 11, 2023
8a1b983
refactor loop unroll into multiple files
tim-hoffman Sep 12, 2023
8e5a642
move memory.rs to interpreter folder
tim-hoffman Sep 12, 2023
aec62f7
remove unused JoinSemiLattice
tim-hoffman Sep 12, 2023
5a235f8
BROKEN: refactor Env and add different cases
tim-hoffman Sep 13, 2023
ce54f80
minor refactoring in bucket interpreter
tim-hoffman Sep 13, 2023
89455e5
fix compile, refactor ContextSwitcher
tim-hoffman Sep 13, 2023
9232425
simplify type for fixed variant parameters
tim-hoffman Sep 14, 2023
7bfdff9
add 'counter_override' for extracted loop body function to access sub…
tim-hoffman Sep 20, 2023
1b3a85b
[VAN-605] handle subcomponents (mostly)
tim-hoffman Sep 21, 2023
678c9eb
formatting
tim-hoffman Sep 21, 2023
90d77c0
update tests related to new JIRA issues 670, 671
tim-hoffman Sep 21, 2023
6ac932b
new subcmp tests and fix a loop test output
tim-hoffman Sep 21, 2023
c6f1d1f
handle buckets that aren't used by every iteration, add tests
tim-hoffman Sep 23, 2023
f0020ef
stabilize test output when some args are null/None
tim-hoffman Sep 25, 2023
776c832
add more IF statement inside a loop test cases
tim-hoffman Sep 25, 2023
8912682
[VAN-677]
tim-hoffman Sep 25, 2023
bb311be
add and improve lit test output checks
tim-hoffman Sep 26, 2023
bf59c04
fix build, happens to be [VAN-673]
tim-hoffman Sep 26, 2023
3715a6a
test comments
tim-hoffman Sep 26, 2023
0ba4952
fix the test I forgot about
tim-hoffman Sep 26, 2023
bd55476
comment out debug lines
tim-hoffman Sep 26, 2023
d860640
fix an unhandled case
tim-hoffman Sep 26, 2023
e83051f
cleanup a bit
tim-hoffman Sep 27, 2023
7cedb67
use different label for flattened loops vs branches
tim-hoffman Sep 27, 2023
bd4f80f
address CR
tim-hoffman Oct 11, 2023
a9c74c1
Merge branch 'llvm' into th/loop-body-extraction
tim-hoffman Oct 11, 2023
73575e7
bring in change from another PR
tim-hoffman Oct 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 10 additions & 17 deletions circom/src/compilation_user.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use ansi_term::Colour;
use circuit_passes::passes::PassManager;
use compiler::compiler_interface;
use compiler::compiler_interface::{Config, VCP};
use compiler::compiler_interface::{self, Config, VCP};
use program_structure::error_definition::Report;
use program_structure::error_code::ReportCode;
use program_structure::file_definition::FileLibrary;
use program_structure::program_archive::ProgramArchive;
use crate::VERSION;


pub struct CompilerConfig {
pub js_folder: String,
pub wasm_name: String,
Expand Down Expand Up @@ -61,28 +59,24 @@ pub fn compile(config: CompilerConfig, program_archive: ProgramArchive, prime: &
}

if config.llvm_flag {
// Only run this passes if we are going to generate LLVM code
// Only run the passes if we are going to generate LLVM code
let pm = PassManager::new();
circuit = pm
.schedule_loop_unroll_pass(prime)
.schedule_conditional_flattening_pass(prime)
.schedule_mapped_to_indexed_pass(prime)
.schedule_unknown_index_sanitization_pass(prime)
.schedule_simplification_pass(prime)
.schedule_deterministic_subcmp_invoke_pass(prime)
.transform_circuit(circuit);
.schedule_loop_unroll_pass()
.schedule_conditional_flattening_pass()
.schedule_mapped_to_indexed_pass()
.schedule_unknown_index_sanitization_pass()
.schedule_simplification_pass()
.schedule_deterministic_subcmp_invoke_pass()
.transform_circuit(circuit, prime);
compiler_interface::write_llvm_ir(
&mut circuit,
&program_archive,
&config.llvm_folder,
&config.llvm_file,
config.clean_llvm,
)?;
println!(
"{} {}",
Colour::Green.paint("Written successfully:"),
config.llvm_file
);
println!("{} {}", Colour::Green.paint("Written successfully:"), config.llvm_file);
}

match (config.wat_flag, config.wasm_flag) {
Expand Down Expand Up @@ -124,7 +118,6 @@ pub fn compile(config: CompilerConfig, program_archive: ProgramArchive, prime: &
Ok(())
}


fn wat_to_wasm(wat_file: &str, wasm_file: &str) -> Result<(), Report> {
use std::fs::read_to_string;
use std::fs::File;
Expand Down
167 changes: 150 additions & 17 deletions circom/tests/loops/call_inside_loop.circom
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
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
// XFAIL: .*
// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s --enable-var-scope

//arena = { a[0], a[1], n, b, c, d, e, f, g}
function fun(a, n, b, c, d, e, f, g) {
var x[5];
for (var i = 0; i < n; i++) {
Expand All @@ -11,6 +11,8 @@ function fun(a, n, b, c, d, e, f, g) {
return x[0] + x[2] + x[4];
}

//signal_arena = { out, in }
//lvars = { m, n, a[0], a[1], b[0], b[1], i }
template CallInLoop(n, m) {
signal input in;
signal output out;
Expand All @@ -27,18 +29,6 @@ template CallInLoop(n, m) {

component main = CallInLoop(2, 3);

//// Use the block labels to check that the loop is NOT unrolled
0xddom marked this conversation as resolved.
Show resolved Hide resolved
//CHECK-LABEL: define i256 @fun_{{[0-9]+}}
//CHECK-SAME: (i256* %[[ARG:[0-9]+]])
//CHECK-NOT: unrolled_loop{{.*}}:
//CHECK: loop.cond{{.*}}:
//CHECK: loop.body{{.*}}:
//CHECK: loop.end{{.*}}:
//CHECK-NOT: unrolled_loop{{.*}}:
//CHECK: }

//signal_arena = { out, in }
//lvars = { m, n, a[0], a[1], i, b[0], b[1] }
//
// var a[2];
// i = 0;
Expand All @@ -54,6 +44,149 @@ component main = CallInLoop(2, 3);
// i = 2;
// out <-- b[0];
//
//CHECK-LABEL: define void @CallInLoop_{{[0-9]+}}_run
//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]])
//CHECK: TODO: Code produced currently is incorrect! See https://veridise.atlassian.net/browse/VAN-611
//CHECK-LABEL: define void @..generated..loop.body.
//CHECK-SAME: [[$F_ID_1:[0-9]+]]([0 x i256]* %lvars, [0 x i256]* %signals, i256* %fix_0){{.*}} {
//CHECK-NEXT: ..generated..loop.body.[[$F_ID_1]]:
//CHECK-NEXT: br label %store1
//CHECK-EMPTY:
//CHECK-NEXT: store1:
//CHECK-NEXT: %0 = getelementptr [0 x i256], [0 x i256]* %signals, i32 0, i32 1
//CHECK-NEXT: %1 = load i256, i256* %0, align 4
//CHECK-NEXT: %call.fr_add = call i256 @fr_add(i256 3, i256 %1)
//CHECK-NEXT: %2 = getelementptr i256, i256* %fix_0, i32 0
//CHECK-NEXT: store i256 %call.fr_add, i256* %2, align 4
//CHECK-NEXT: br label %store2
//CHECK-EMPTY:
//CHECK-NEXT: store2:
//CHECK-NEXT: %3 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 4
//CHECK-NEXT: %4 = load i256, i256* %3, align 4
//CHECK-NEXT: %call.fr_add1 = call i256 @fr_add(i256 %4, i256 1)
//CHECK-NEXT: %5 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 4
//CHECK-NEXT: store i256 %call.fr_add1, i256* %5, align 4
//CHECK-NEXT: br label %return3
//CHECK-EMPTY:
//CHECK-NEXT: return3:
//CHECK-NEXT: ret void
//CHECK-NEXT: }
//
//CHECK-LABEL: define void @..generated..loop.body.
//CHECK-SAME: [[$F_ID_2:[0-9]+]]([0 x i256]* %lvars, [0 x i256]* %signals){{.*}} {
//CHECK-NEXT: ..generated..loop.body.[[$F_ID_2]]:
//CHECK-NEXT: br label %call1
//CHECK-EMPTY:
//CHECK-NEXT: call1:
//CHECK-NEXT: %fun_0_arena = alloca [15 x i256], align 8
//CHECK-NEXT: %0 = getelementptr [15 x i256], [15 x i256]* %fun_0_arena, i32 0, i32 0
//CHECK-NEXT: %1 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: call void @fr_copy_n(i256* %1, i256* %0, i32 2)
//CHECK-NEXT: %2 = getelementptr [15 x i256], [15 x i256]* %fun_0_arena, i32 0, i32 2
//CHECK-NEXT: store i256 2, i256* %2, align 4
//CHECK-NEXT: %3 = getelementptr [15 x i256], [15 x i256]* %fun_0_arena, i32 0, i32 3
//CHECK-NEXT: store i256 3, i256* %3, align 4
//CHECK-NEXT: %4 = getelementptr [15 x i256], [15 x i256]* %fun_0_arena, i32 0, i32 4
//CHECK-NEXT: store i256 3, i256* %4, align 4
//CHECK-NEXT: %5 = getelementptr [15 x i256], [15 x i256]* %fun_0_arena, i32 0, i32 5
//CHECK-NEXT: store i256 3, i256* %5, align 4
//CHECK-NEXT: %6 = getelementptr [15 x i256], [15 x i256]* %fun_0_arena, i32 0, i32 6
//CHECK-NEXT: store i256 3, i256* %6, align 4
//CHECK-NEXT: %7 = getelementptr [15 x i256], [15 x i256]* %fun_0_arena, i32 0, i32 7
//CHECK-NEXT: store i256 3, i256* %7, align 4
//CHECK-NEXT: %8 = getelementptr [15 x i256], [15 x i256]* %fun_0_arena, i32 0, i32 8
//CHECK-NEXT: store i256 3, i256* %8, align 4
//CHECK-NEXT: %9 = bitcast [15 x i256]* %fun_0_arena to i256*
//CHECK-NEXT: %call.fun_0 = call i256 @fun_0(i256* %9)
//CHECK-NEXT: %10 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 6
//CHECK-NEXT: %11 = load i256, i256* %10, align 4
//CHECK-NEXT: %call.fr_cast_to_addr = call i32 @fr_cast_to_addr(i256 %11)
//CHECK-NEXT: %mul_addr = mul i32 1, %call.fr_cast_to_addr
//CHECK-NEXT: %add_addr = add i32 %mul_addr, 4
//CHECK-NEXT: %12 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 %add_addr
//CHECK-NEXT: store i256 %call.fun_0, i256* %12, align 4
//CHECK-NEXT: br label %store2
//CHECK-EMPTY:
//CHECK-NEXT: store2:
//CHECK-NEXT: %13 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 6
//CHECK-NEXT: %14 = load i256, i256* %13, align 4
//CHECK-NEXT: %call.fr_add = call i256 @fr_add(i256 %14, i256 1)
//CHECK-NEXT: %15 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 6
//CHECK-NEXT: store i256 %call.fr_add, i256* %15, align 4
//CHECK-NEXT: br label %return3
//CHECK-EMPTY:
//CHECK-NEXT: return3:
//CHECK-NEXT: ret void
//CHECK-NEXT: }
//
//CHECK-LABEL: define void @CallInLoop_{{[0-9]+}}_run([0 x i256]* %0){{.*}} {
//CHECK-NEXT: prelude:
//CHECK-NEXT: %lvars = alloca [7 x i256], align 8
//CHECK-NEXT: %subcmps = alloca [0 x { [0 x i256]*, i32 }], align 8
//CHECK-NEXT: br label %store1
//CHECK-EMPTY:
//CHECK-NEXT: store1:
//CHECK-NEXT: %1 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 0
//CHECK-NEXT: store i256 3, i256* %1, align 4
//CHECK-NEXT: br label %store2
//CHECK-EMPTY:
//CHECK-NEXT: store2:
//CHECK-NEXT: %2 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 1
//CHECK-NEXT: store i256 2, i256* %2, align 4
//CHECK-NEXT: br label %store3
//CHECK-EMPTY:
//CHECK-NEXT: store3:
//CHECK-NEXT: %3 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: store i256 0, i256* %3, align 4
//CHECK-NEXT: br label %store4
//CHECK-EMPTY:
//CHECK-NEXT: store4:
//CHECK-NEXT: %4 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 3
//CHECK-NEXT: store i256 0, i256* %4, align 4
//CHECK-NEXT: br label %store5
//CHECK-EMPTY:
//CHECK-NEXT: store5:
//CHECK-NEXT: %5 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 4
//CHECK-NEXT: store i256 0, i256* %5, align 4
//CHECK-NEXT: br label %unrolled_loop6
//CHECK-EMPTY:
//CHECK-NEXT: unrolled_loop6:
//CHECK-NEXT: %6 = bitcast [7 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: %7 = bitcast [7 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: %8 = getelementptr [0 x i256], [0 x i256]* %7, i32 0, i256 2
//CHECK-NEXT: call void @..generated..loop.body.[[$F_ID_1]]([0 x i256]* %6, [0 x i256]* %0, i256* %8)
//CHECK-NEXT: %9 = bitcast [7 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: %10 = bitcast [7 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: %11 = getelementptr [0 x i256], [0 x i256]* %10, i32 0, i256 3
//CHECK-NEXT: call void @..generated..loop.body.[[$F_ID_1]]([0 x i256]* %9, [0 x i256]* %0, i256* %11)
//CHECK-NEXT: br label %store7
//CHECK-EMPTY:
//CHECK-NEXT: store7:
//CHECK-NEXT: %12 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 4
//CHECK-NEXT: store i256 0, i256* %12, align 4
//CHECK-NEXT: br label %store8
//CHECK-EMPTY:
//CHECK-NEXT: store8:
//CHECK-NEXT: %13 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 5
//CHECK-NEXT: store i256 0, i256* %13, align 4
//CHECK-NEXT: br label %store9
//CHECK-EMPTY:
//CHECK-NEXT: store9:
//CHECK-NEXT: %14 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 6
//CHECK-NEXT: store i256 0, i256* %14, align 4
//CHECK-NEXT: br label %unrolled_loop10
//CHECK-EMPTY:
//CHECK-NEXT: unrolled_loop10:
//CHECK-NEXT: %15 = bitcast [7 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: call void @..generated..loop.body.[[$F_ID_2]]([0 x i256]* %15, [0 x i256]* %0)
//CHECK-NEXT: %16 = bitcast [7 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: call void @..generated..loop.body.[[$F_ID_2]]([0 x i256]* %16, [0 x i256]* %0)
//CHECK-NEXT: br label %store11
//CHECK-EMPTY:
//CHECK-NEXT: store11:
//CHECK-NEXT: %17 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 4
//CHECK-NEXT: %18 = load i256, i256* %17, align 4
//CHECK-NEXT: %19 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK-NEXT: store i256 %18, i256* %19, align 4
//CHECK-NEXT: br label %prologue
//CHECK-EMPTY:
//CHECK-NEXT: prologue:
//CHECK-NEXT: ret void
//CHECK-NEXT: }
2 changes: 1 addition & 1 deletion circom/tests/loops/fib_input.circom
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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
// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s --enable-var-scope

template Fibonacci() {
signal input nth_fib;
Expand Down
2 changes: 1 addition & 1 deletion circom/tests/loops/fib_template.circom
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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
// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s --enable-var-scope

template FibonacciTmpl(N) {
signal output out;
Expand Down
2 changes: 1 addition & 1 deletion circom/tests/loops/for_known.circom
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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
// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s --enable-var-scope

template ForKnown(N) {
signal output out;
Expand Down
2 changes: 1 addition & 1 deletion circom/tests/loops/for_unknown.circom
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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
// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s --enable-var-scope

template ForUnknown() {
signal input in;
Expand Down
2 changes: 1 addition & 1 deletion circom/tests/loops/for_unknown_index.circom
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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
// RUN: rm -rf %t && mkdir %t && %circom --llvm -o %t %s | sed -n 's/.*Written successfully:.* \(.*\)/\1/p' | xargs cat | FileCheck %s --enable-var-scope

template ForUnknownIndex() {
signal input in;
Expand Down
Loading
Loading