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

Add regression tests for loop unrolling #49

Merged
merged 1 commit into from
Aug 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 13 additions & 3 deletions 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
// 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;
Expand All @@ -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;
Expand All @@ -22,4 +22,14 @@ template Fibonacci() {
out <-- (nth_fib == 0) ? 0 : (nth_fib == 1 ? 1 : a + b);
}

component main = Fibonacci();
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: }
22 changes: 19 additions & 3 deletions 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
// 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;
Expand All @@ -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;
Expand All @@ -27,4 +27,20 @@ template FibonacciTmpl(N) {
}
}

component main = FibonacciTmpl(5);
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: }
20 changes: 18 additions & 2 deletions 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
// 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;
Expand All @@ -13,4 +13,20 @@ template ForKnown(N) {
out <-- acc;
}

component main = ForKnown(10);
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: }
14 changes: 12 additions & 2 deletions 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
// 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;
Expand All @@ -14,4 +14,14 @@ template ForUnknown() {
out <-- acc;
}

component main = ForUnknown();
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: }
14 changes: 12 additions & 2 deletions 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
// 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;
Expand All @@ -17,4 +17,14 @@ template ForUnknownIndex() {
out <-- arr[acc];
}

component main = ForUnknownIndex();
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: }
71 changes: 68 additions & 3 deletions circom/tests/loops/inner_loops.circom
Original file line number Diff line number Diff line change
@@ -1,16 +1,81 @@
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];
var b[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);
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: }
2 changes: 1 addition & 1 deletion circom/tests/loops/inner_loops2.circom
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ template InnerLoops(n) {
i++; // 5
}

component main = InnerLoops(5);
component main = InnerLoops(5);
2 changes: 1 addition & 1 deletion circom/tests/loops/inner_loops3.circom
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ template InnerLoops(n) {
}
}

component main = InnerLoops(5);
component main = InnerLoops(5);
2 changes: 1 addition & 1 deletion circom/tests/loops/inner_loops4.circom
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ template InnerLoops(n) {
}
}

component main = InnerLoops(2);
component main = InnerLoops(2);
48 changes: 48 additions & 0 deletions circom/tests/loops/known_function.circom
Original file line number Diff line number Diff line change
@@ -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
39 changes: 39 additions & 0 deletions circom/tests/loops/known_signal_value.circom
Original file line number Diff line number Diff line change
@@ -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: }
14 changes: 12 additions & 2 deletions circom/tests/loops/unknown_local_array_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
// 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;
Expand All @@ -20,4 +20,14 @@ template ForUnknownIndex() {
out <-- arr2[acc % 10];
}

component main = ForUnknownIndex();
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: }
Loading
Loading