Skip to content

Commit

Permalink
Various fixes for benchmarks (#62)
Browse files Browse the repository at this point in the history
* skip body extraction when the loop has 0 iterations
* Modify interpreter to distinguish between circom functions and loop body functions
* [VAN-676] duplicate extracted functions when flattening branch buckets
* [VAN-670] generate and flatten subcmp counter/run
* impl Debug for Env to be more friendly, expand on test case comment
* remove debug println
* fix: conditions not flattening in non-generated methods
* [VAN-582] properly convert mapped to indexed when there are multiple versions of the subcomponent
* fix XFAIL test outputs so they pass
* add test cases
* handle CallBucket return case in mapped_to_indexed
* fix body_extractor assertion failure
* fix segfault from improper GEP
* use BucketId as key to speed up SimplificationPass
* fix function name to reflect actual usage
* Remove functions that cannot be reached from any template
Co-authored-by: Daniel Dominguez <[email protected]>
  • Loading branch information
tim-hoffman committed Nov 8, 2023
1 parent 6b07e63 commit 632ebbb
Show file tree
Hide file tree
Showing 54 changed files with 4,084 additions and 1,062 deletions.
1 change: 1 addition & 0 deletions circom/src/compilation_user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ pub fn compile(config: CompilerConfig, program_archive: ProgramArchive, prime: &
.schedule_const_arg_deduplication_pass()
.schedule_loop_unroll_pass()
.schedule_conditional_flattening_pass()
.schedule_unused_function_removal_pass() //previous 2 passes create the dead functions
.schedule_mapped_to_indexed_pass()
.schedule_unknown_index_sanitization_pass()
.schedule_simplification_pass()
Expand Down
148 changes: 148 additions & 0 deletions circom/tests/loops/assign_in_loop_1.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
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 --enable-var-scope

template Inner() {
signal input in;
signal output out;

out <-- in & 1;
}

template Num2Bits(n) {
signal input in;
signal output out[n];

component c[n];
for (var i = 0; i < n; i++) {
c[i] = Inner();
c[i].in <-- in;
out[i] <-- c[i].out;
}
}

component main = Num2Bits(3);

//CHECK-LABEL: define void @..generated..loop.body.{{[0-9]+\.T}}([0 x i256]* %lvars, [0 x i256]* %signals,
//CHECK-SAME: i256* %subfix_[[X1:[0-9]+]], i256* %fix_[[X2:[0-9]+]], i256* %subfix_[[X3:[0-9]+]],
//CHECK-SAME: [0 x i256]* %sub_[[X3]], i256* %subc_[[X3]]){{.*}} {
//CHECK-NEXT: ..generated..loop.body.[[$F_ID_1:[0-9]+\.T]]:
//CHECK-NEXT: br label %store1
//CHECK-EMPTY:
//CHECK-NEXT: store1:
//CHECK-NEXT: %0 = getelementptr [0 x i256], [0 x i256]* %signals, i32 0, i32 3
//CHECK-NEXT: %1 = load i256, i256* %0, align 4
//CHECK-NEXT: %2 = getelementptr i256, i256* %subfix_[[X1]], i32 0
//CHECK-NEXT: store i256 %1, i256* %2, align 4
//CHECK-NEXT: br label %store2
//CHECK-EMPTY:
//CHECK-NEXT: store2:
//CHECK-NEXT: %3 = load i256, i256* %subc_[[X3]], align 4
//CHECK-NEXT: %call.fr_sub = call i256 @fr_sub(i256 %3, i256 1)
//CHECK-NEXT: %4 = getelementptr i256, i256* %subc_[[X3]], i32 0
//CHECK-NEXT: store i256 %call.fr_sub, i256* %4, align 4
//CHECK-NEXT: br label %fold_true3
//CHECK-EMPTY:
//CHECK-NEXT: fold_true3:
//CHECK-NEXT: call void @llvm.donothing()
//CHECK-NEXT: call void @Inner_0_run([0 x i256]* %sub_[[X3]])
//CHECK-NEXT: br label %store4
//CHECK-EMPTY:
//CHECK-NEXT: store4:
//CHECK-NEXT: %5 = getelementptr i256, i256* %subfix_[[X3]], i32 0
//CHECK-NEXT: %6 = load i256, i256* %5, align 4
//CHECK-NEXT: %7 = getelementptr i256, i256* %fix_[[X2]], i32 0
//CHECK-NEXT: store i256 %6, i256* %7, align 4
//CHECK-NEXT: br label %store5
//CHECK-EMPTY:
//CHECK-NEXT: store5:
//CHECK-NEXT: %8 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 1
//CHECK-NEXT: %9 = load i256, i256* %8, align 4
//CHECK-NEXT: %call.fr_add = call i256 @fr_add(i256 %9, i256 1)
//CHECK-NEXT: %10 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 1
//CHECK-NEXT: store i256 %call.fr_add, i256* %10, align 4
//CHECK-NEXT: br label %return6
//CHECK-EMPTY:
//CHECK-NEXT: return6:
//CHECK-NEXT: ret void
//CHECK-NEXT: }
//
//CHECK-LABEL: define void @Num2Bits_{{[0-9]+}}_run([0 x i256]* %0){{.*}} {
//CHECK-NEXT: prelude:
//CHECK-NEXT: %lvars = alloca [2 x i256], align 8
//CHECK-NEXT: %subcmps = alloca [3 x { [0 x i256]*, i32 }], align 8
//CHECK-NEXT: br label %store1
//CHECK-EMPTY:
//CHECK-NEXT: store1:
//CHECK-NEXT: %1 = getelementptr [2 x i256], [2 x i256]* %lvars, i32 0, i32 0
//CHECK-NEXT: store i256 3, i256* %1, align 4
//CHECK-NEXT: br label %create_cmp2
//CHECK-EMPTY:
//CHECK-NEXT: create_cmp2:
//CHECK-NEXT: %2 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 0
//CHECK-NEXT: call void @Inner_0_build({ [0 x i256]*, i32 }* %2)
//CHECK-NEXT: %3 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 1
//CHECK-NEXT: call void @Inner_0_build({ [0 x i256]*, i32 }* %3)
//CHECK-NEXT: %4 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 2
//CHECK-NEXT: call void @Inner_0_build({ [0 x i256]*, i32 }* %4)
//CHECK-NEXT: br label %store3
//CHECK-EMPTY:
//CHECK-NEXT: store3:
//CHECK-NEXT: %5 = getelementptr [2 x i256], [2 x i256]* %lvars, i32 0, i32 1
//CHECK-NEXT: store i256 0, i256* %5, align 4
//CHECK-NEXT: br label %unrolled_loop4
//CHECK-EMPTY:
//CHECK-NEXT: unrolled_loop4:
//CHECK-NEXT: %6 = bitcast [2 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: %7 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 0, i32 0
//CHECK-NEXT: %8 = load [0 x i256]*, [0 x i256]** %7, align 8
//CHECK-NEXT: %9 = getelementptr [0 x i256], [0 x i256]* %8, i32 0
//CHECK-NEXT: %10 = getelementptr [0 x i256], [0 x i256]* %9, i32 0, i256 1
//CHECK-NEXT: %11 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i256 0
//CHECK-NEXT: %12 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 0, i32 0
//CHECK-NEXT: %13 = load [0 x i256]*, [0 x i256]** %12, align 8
//CHECK-NEXT: %14 = getelementptr [0 x i256], [0 x i256]* %13, i32 0
//CHECK-NEXT: %15 = getelementptr [0 x i256], [0 x i256]* %14, i32 0, i256 0
//CHECK-NEXT: %16 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 0, i32 0
//CHECK-NEXT: %17 = load [0 x i256]*, [0 x i256]** %16, align 8
//CHECK-NEXT: %18 = getelementptr [0 x i256], [0 x i256]* %17, i32 0
//CHECK-NEXT: %19 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 0, i32 1
//CHECK-NEXT: %20 = bitcast i32* %19 to i256*
//CHECK-NEXT: call void @..generated..loop.body.[[$F_ID_1]]([0 x i256]* %6, [0 x i256]* %0, i256* %10, i256* %11, i256* %15, [0 x i256]* %18, i256* %20)
//CHECK-NEXT: %21 = bitcast [2 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: %22 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 1, i32 0
//CHECK-NEXT: %23 = load [0 x i256]*, [0 x i256]** %22, align 8
//CHECK-NEXT: %24 = getelementptr [0 x i256], [0 x i256]* %23, i32 0
//CHECK-NEXT: %25 = getelementptr [0 x i256], [0 x i256]* %24, i32 0, i256 1
//CHECK-NEXT: %26 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i256 1
//CHECK-NEXT: %27 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 1, i32 0
//CHECK-NEXT: %28 = load [0 x i256]*, [0 x i256]** %27, align 8
//CHECK-NEXT: %29 = getelementptr [0 x i256], [0 x i256]* %28, i32 0
//CHECK-NEXT: %30 = getelementptr [0 x i256], [0 x i256]* %29, i32 0, i256 0
//CHECK-NEXT: %31 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 1, i32 0
//CHECK-NEXT: %32 = load [0 x i256]*, [0 x i256]** %31, align 8
//CHECK-NEXT: %33 = getelementptr [0 x i256], [0 x i256]* %32, i32 0
//CHECK-NEXT: %34 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 1, i32 1
//CHECK-NEXT: %35 = bitcast i32* %34 to i256*
//CHECK-NEXT: call void @..generated..loop.body.[[$F_ID_1]]([0 x i256]* %21, [0 x i256]* %0, i256* %25, i256* %26, i256* %30, [0 x i256]* %33, i256* %35)
//CHECK-NEXT: %36 = bitcast [2 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: %37 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 2, i32 0
//CHECK-NEXT: %38 = load [0 x i256]*, [0 x i256]** %37, align 8
//CHECK-NEXT: %39 = getelementptr [0 x i256], [0 x i256]* %38, i32 0
//CHECK-NEXT: %40 = getelementptr [0 x i256], [0 x i256]* %39, i32 0, i256 1
//CHECK-NEXT: %41 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i256 2
//CHECK-NEXT: %42 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 2, i32 0
//CHECK-NEXT: %43 = load [0 x i256]*, [0 x i256]** %42, align 8
//CHECK-NEXT: %44 = getelementptr [0 x i256], [0 x i256]* %43, i32 0
//CHECK-NEXT: %45 = getelementptr [0 x i256], [0 x i256]* %44, i32 0, i256 0
//CHECK-NEXT: %46 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 2, i32 0
//CHECK-NEXT: %47 = load [0 x i256]*, [0 x i256]** %46, align 8
//CHECK-NEXT: %48 = getelementptr [0 x i256], [0 x i256]* %47, i32 0
//CHECK-NEXT: %49 = getelementptr [3 x { [0 x i256]*, i32 }], [3 x { [0 x i256]*, i32 }]* %subcmps, i32 0, i32 2, i32 1
//CHECK-NEXT: %50 = bitcast i32* %49 to i256*
//CHECK-NEXT: call void @..generated..loop.body.[[$F_ID_1]]([0 x i256]* %36, [0 x i256]* %0, i256* %40, i256* %41, i256* %45, [0 x i256]* %48, i256* %50)
//CHECK-NEXT: br label %prologue
//CHECK-EMPTY:
//CHECK-NEXT: prologue:
//CHECK-NEXT: ret void
//CHECK-NEXT: }
46 changes: 46 additions & 0 deletions circom/tests/loops/assign_in_loop_2.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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 --enable-var-scope

// References to the Inner subcmp use LocationRule::Mapped because of the 'i' parameter
template Inner(i) {
signal input in;
signal output out;

out <-- in & i;
}

template Num2Bits(n) {
signal input in;
signal output out[n];

component c[n];
for (var i = 0; i < n; i++) {
c[i] = Inner(i);
c[i].in <-- in;
out[i] <-- c[i].out;
}
}

component main = Num2Bits(3);

//CHECK-LABEL: define void @Inner_{{[0-9]+}}_build({ [0 x i256]*, i32 }* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_
//CHECK-SAME: [[$RUN_1:[0-9]+]]_run([0 x i256]* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_{{[0-9]+}}_build({ [0 x i256]*, i32 }* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_
//CHECK-SAME: [[$RUN_2:[0-9]+]]_run([0 x i256]* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_{{[0-9]+}}_build({ [0 x i256]*, i32 }* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_
//CHECK-SAME: [[$RUN_3:[0-9]+]]_run([0 x i256]* %0){{.*}} {
//
//CHECK-LABEL: define void @Num2Bits_{{[0-9]+}}_run([0 x i256]* %0){{.*}} {
//CHECK: unrolled_loop{{[0-9]+}}:
//CHECK: call void @Inner_[[$RUN_1]]_run([0 x i256]* %
//CHECK: call void @Inner_[[$RUN_2]]_run([0 x i256]* %
//CHECK: call void @Inner_[[$RUN_3]]_run([0 x i256]* %
46 changes: 46 additions & 0 deletions circom/tests/loops/assign_in_loop_3.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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 --enable-var-scope

// References to the Inner subcmp use LocationRule::Mapped because of the 'i' parameter
template Inner(i,j) {
signal input in;
signal output out;

out <-- (in >> i) & j;
}

template Num2Bits(n) {
signal input in;
signal output out[n];

component c[n];
for (var i = 0; i < n; i++) {
c[i] = Inner(i, i+1);
c[i].in <-- in;
out[i] <-- c[i].out;
}
}

component main = Num2Bits(3);

//CHECK-LABEL: define void @Inner_{{[0-9]+}}_build({ [0 x i256]*, i32 }* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_
//CHECK-SAME: [[$RUN_1:[0-9]+]]_run([0 x i256]* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_{{[0-9]+}}_build({ [0 x i256]*, i32 }* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_
//CHECK-SAME: [[$RUN_2:[0-9]+]]_run([0 x i256]* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_{{[0-9]+}}_build({ [0 x i256]*, i32 }* %0){{.*}} {
//
//CHECK-LABEL: define void @Inner_
//CHECK-SAME: [[$RUN_3:[0-9]+]]_run([0 x i256]* %0){{.*}} {
//
//CHECK-LABEL: define void @Num2Bits_{{[0-9]+}}_run([0 x i256]* %0){{.*}} {
//CHECK: unrolled_loop{{[0-9]+}}:
//CHECK: call void @Inner_[[$RUN_1]]_run([0 x i256]* %
//CHECK: call void @Inner_[[$RUN_2]]_run([0 x i256]* %
//CHECK: call void @Inner_[[$RUN_3]]_run([0 x i256]* %
35 changes: 17 additions & 18 deletions circom/tests/loops/call_inside_loop.circom
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ component main = CallInLoop(2, 3);
//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-SAME: [[$F_ID_2:[0-9]+]]([0 x i256]* %lvars, [0 x i256]* %signals, i256* %fix_0){{.*}} {
//CHECK-NEXT: ..generated..loop.body.[[$F_ID_2]]:
//CHECK-NEXT: br label %call1
//CHECK-EMPTY:
Expand All @@ -95,21 +95,16 @@ component main = CallInLoop(2, 3);
//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: %10 = getelementptr i256, i256* %fix_0, i32 0
//CHECK-NEXT: store i256 %call.fun_0, i256* %10, align 4
//CHECK-NEXT: br label %store2
//CHECK-EMPTY:
//CHECK-NEXT: store2:
//CHECK-NEXT: %11 = getelementptr [0 x i256], [0 x i256]* %lvars, i32 0, i32 6
//CHECK-NEXT: %12 = load i256, i256* %11, align 4
//CHECK-NEXT: %call.fr_add = call i256 @fr_add(i256 %12, i256 1)
//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: store i256 %call.fr_add, i256* %13, align 4
//CHECK-NEXT: br label %return3
//CHECK-EMPTY:
//CHECK-NEXT: return3:
Expand Down Expand Up @@ -175,16 +170,20 @@ component main = CallInLoop(2, 3);
//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: %17 = getelementptr [0 x i256], [0 x i256]* %16, i32 0, i256 4
//CHECK-NEXT: call void @..generated..loop.body.[[$F_ID_2]]([0 x i256]* %15, [0 x i256]* %0, i256* %17)
//CHECK-NEXT: %18 = bitcast [7 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: %19 = bitcast [7 x i256]* %lvars to [0 x i256]*
//CHECK-NEXT: %20 = getelementptr [0 x i256], [0 x i256]* %19, i32 0, i256 5
//CHECK-NEXT: call void @..generated..loop.body.[[$F_ID_2]]([0 x i256]* %18, [0 x i256]* %0, i256* %20)
//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: %21 = getelementptr [7 x i256], [7 x i256]* %lvars, i32 0, i32 4
//CHECK-NEXT: %22 = load i256, i256* %21, align 4
//CHECK-NEXT: %23 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK-NEXT: store i256 %22, i256* %23, align 4
//CHECK-NEXT: br label %prologue
//CHECK-EMPTY:
//CHECK-NEXT: prologue:
Expand Down
Loading

0 comments on commit 632ebbb

Please sign in to comment.