Skip to content

Commit

Permalink
Additional tests for current state of loop unrolling (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-hoffman authored Aug 29, 2023
1 parent 19a4e02 commit 5da5ac4
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 2 deletions.
2 changes: 1 addition & 1 deletion circom/tests/calls/call2.circom
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ template Call2() {
y <-- nbits(m);
}

component main = Call2();
component main = Call2();
21 changes: 21 additions & 0 deletions circom/tests/calls/call_with_array.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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: .*

function sum(a) {
return a[0] + a[1] + a[2] + a[3];
}

template CallWithArray() {
signal input x[4];
signal output y;

y <-- sum(x);
}

component main = CallWithArray();

//CHECK-LABEL: define void @CallWithArray_{{[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
2 changes: 1 addition & 1 deletion circom/tests/calls/unk_function_call.circom
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,4 @@ template BigModInv51() {
}
}

component main = BigModInv51();
component main = BigModInv51();
59 changes: 59 additions & 0 deletions circom/tests/loops/call_inside_loop.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
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: .*

function fun(a, n, b, c, d, e, f, g) {
var x[5];
for (var i = 0; i < n; i++) {
x[i] = a[i] + b + c + d + e + f;
}
return x[0] + x[2] + x[4];
}

template CallInLoop(n, m) {
signal input in;
signal output out;
var a[n];
for (var i = 0; i < n; i++) {
a[i] = m + in;
}
var b[n];
for (var i = 0; i < n; i++) {
b[i] = fun(a, n, m, m, m, m, m, m);
}
out <-- b[0];
}

component main = CallInLoop(2, 3);

//// Use the block labels to check that the loop is NOT unrolled
//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;
// a[0] = 3 + in;
// i = 1;
// a[1] = 3 + in;
// i = 2;
// var b[2];
// i = 0;
// b[0] = fun(a, 2, 3, 3, 3, 3, 3, 3);
// i = 1;
// b[1] = fun(a, 2, 3, 3, 3, 3, 3, 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
77 changes: 77 additions & 0 deletions circom/tests/loops/inner_loop_simple.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
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 InnerLoops(n, m) {
signal input in[m];
signal output out;
var b[n];

for (var i = 0; i < n; i++) {
for (var j = 0; j < m; j++) {
b[i] = in[j];
}
}
out <-- b[0];
}

component main = InnerLoops(2, 3);

//signal_arena = { out, in[0], in[1], in[2] }
//lvars = { n, m, b[0], b[1], i, j }

//CHECK-LABEL: define void @InnerLoops_{{[0-9]+}}_run
//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]])
//CHECK: unrolled_loop{{[0-9]+}}:
//CHECK-NEXT: %[[T06:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 5
//CHECK-NEXT: store i256 0, i256* %{{.*}}[[T06]], align 4
//CHECK-NEXT: %[[T07:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 1
//CHECK-NEXT: %[[T08:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T07]], align 4
//CHECK-NEXT: %[[T09:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: store i256 %{{.*}}[[T08]], i256* %{{.*}}[[T09]], align 4
//CHECK-NEXT: %[[T10:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 5
//CHECK-NEXT: store i256 1, i256* %{{.*}}[[T10]], align 4
//CHECK-NEXT: %[[T11:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 2
//CHECK-NEXT: %[[T12:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T11]], align 4
//CHECK-NEXT: %[[T13:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: store i256 %{{.*}}[[T12]], i256* %{{.*}}[[T13]], align 4
//CHECK-NEXT: %[[T14:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 5
//CHECK-NEXT: store i256 2, i256* %{{.*}}[[T14]], align 4
//CHECK-NEXT: %[[T15:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 3
//CHECK-NEXT: %[[T16:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T15]], align 4
//CHECK-NEXT: %[[T17:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: store i256 %{{.*}}[[T16]], i256* %{{.*}}[[T17]], align 4
//CHECK-NEXT: %[[T18:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 5
//CHECK-NEXT: store i256 3, i256* %{{.*}}[[T18]], align 4
//CHECK-NEXT: %[[T19:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 4
//CHECK-NEXT: store i256 1, i256* %{{.*}}[[T19]], align 4
//CHECK-NEXT: %[[T20:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 5
//CHECK-NEXT: store i256 0, i256* %{{.*}}[[T20]], align 4
//CHECK-NEXT: %[[T21:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 1
//CHECK-NEXT: %[[T22:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T21]], align 4
//CHECK-NEXT: %[[T23:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 3
//CHECK-NEXT: store i256 %{{.*}}[[T22]], i256* %{{.*}}[[T23]], align 4
//CHECK-NEXT: %[[T24:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 5
//CHECK-NEXT: store i256 1, i256* %{{.*}}[[T24]], align 4
//CHECK-NEXT: %[[T25:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 2
//CHECK-NEXT: %[[T26:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T25]], align 4
//CHECK-NEXT: %[[T27:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 3
//CHECK-NEXT: store i256 %{{.*}}[[T26]], i256* %{{.*}}[[T27]], align 4
//CHECK-NEXT: %[[T28:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 5
//CHECK-NEXT: store i256 2, i256* %{{.*}}[[T28]], align 4
//CHECK-NEXT: %[[T29:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 3
//CHECK-NEXT: %[[T30:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T29]], align 4
//CHECK-NEXT: %[[T31:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 3
//CHECK-NEXT: store i256 %{{.*}}[[T30]], i256* %{{.*}}[[T31]], align 4
//CHECK-NEXT: %[[T32:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 5
//CHECK-NEXT: store i256 3, i256* %{{.*}}[[T32]], align 4
//CHECK-NEXT: %[[T33:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 4
//CHECK-NEXT: store i256 2, i256* %{{.*}}[[T33]], align 4
//CHECK-NEXT: br label %store[[LBL:[0-9]+]]
//CHECK-EMPTY:
//CHECK-NEXT: store{{.*}}[[LBL]]:
//CHECK-NEXT: %[[T34:[[:alnum:]_.]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: %[[T35:[[:alnum:]_.]+]] = load i256, i256* %{{.*}}[[T34]], align 4
//CHECK-NEXT: %[[T36:[[:alnum:]_.]+]] = getelementptr [0 x i256], [0 x i256]* %{{.*}}[[ARG]], i32 0, i32 0
//CHECK-NEXT: store i256 %{{.*}}[[T35]], i256* %{{.*}}[[T36]], align 4
//CHECK: }
93 changes: 93 additions & 0 deletions circom/tests/loops/vanguard-uc-comp.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
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 Num2Bits(n) {
signal input in;
signal output out[n];

var lc1=0;
var e2=1;
for (var i = 0; i<n; i++) {
out[i] <-- (in >> i) & 1;
out[i] * (out[i] -1 ) === 0;
lc1 += out[i] * e2;
e2 = e2+e2;
}

lc1 === in;
}

component main = Num2Bits(2);

// %arena (i.e. %0 param) = [ out[0], out[1], in ]
// %lvars = [ n, lc1, e2, i ]
// %subcmps = []
//
//CHECK-LABEL: define void @Num2Bits_{{[0-9]+}}_run
//CHECK-SAME: ([0 x i256]* %[[ARG:[0-9]+]])
//CHECK: unrolled_loop{{[0-9]+}}:
//CHECK-NEXT: %5 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 2
//CHECK-NEXT: %6 = load i256, i256* %5, align 4
//CHECK-NEXT: %7 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 3
//CHECK-NEXT: %8 = load i256, i256* %7, align 4
//CHECK-NEXT: %call.fr_shr = call i256 @fr_shr(i256 %6, i256 %8)
//CHECK-NEXT: %call.fr_bit_and = call i256 @fr_bit_and(i256 %call.fr_shr, i256 1)
//CHECK-NEXT: %9 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK-NEXT: store i256 %call.fr_bit_and, i256* %9, align 4
//CHECK-NEXT: %10 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK-NEXT: %11 = load i256, i256* %10, align 4
//CHECK-NEXT: %12 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK-NEXT: %13 = load i256, i256* %12, align 4
//CHECK-NEXT: %call.fr_sub = call i256 @fr_sub(i256 %13, i256 1)
//CHECK-NEXT: %call.fr_mul = call i256 @fr_mul(i256 %11, i256 %call.fr_sub)
//CHECK-NEXT: %call.fr_eq = call i1 @fr_eq(i256 %call.fr_mul, i256 0)
//CHECK-NEXT: call void @__assert(i1 %call.fr_eq)
//CHECK-NEXT: %constraint = alloca i1, align 1
//CHECK-NEXT: call void @__constraint_value(i1 %call.fr_eq, i1* %constraint)
//CHECK-NEXT: %14 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 1
//CHECK-NEXT: %15 = load i256, i256* %14, align 4
//CHECK-NEXT: %16 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK-NEXT: %17 = load i256, i256* %16, align 4
//CHECK-NEXT: %18 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: %19 = load i256, i256* %18, align 4
//CHECK-NEXT: %call.fr_mul1 = call i256 @fr_mul(i256 %17, i256 %19)
//CHECK-NEXT: %call.fr_add = call i256 @fr_add(i256 %15, i256 %call.fr_mul1)
//CHECK-NEXT: %20 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 1
//CHECK-NEXT: store i256 %call.fr_add, i256* %20, align 4
//CHECK-NEXT: %21 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: store i256 2, i256* %21, align 4
//CHECK-NEXT: %22 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 3
//CHECK-NEXT: store i256 1, i256* %22, align 4
//CHECK-NEXT: %23 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 2
//CHECK-NEXT: %24 = load i256, i256* %23, align 4
//CHECK-NEXT: %25 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 3
//CHECK-NEXT: %26 = load i256, i256* %25, align 4
//CHECK-NEXT: %call.fr_shr2 = call i256 @fr_shr(i256 %24, i256 %26)
//CHECK-NEXT: %call.fr_bit_and3 = call i256 @fr_bit_and(i256 %call.fr_shr2, i256 1)
//CHECK-NEXT: %27 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 1
//CHECK-NEXT: store i256 %call.fr_bit_and3, i256* %27, align 4
//CHECK-NEXT: %28 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 1
//CHECK-NEXT: %29 = load i256, i256* %28, align 4
//CHECK-NEXT: %30 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 1
//CHECK-NEXT: %31 = load i256, i256* %30, align 4
//CHECK-NEXT: %call.fr_sub4 = call i256 @fr_sub(i256 %31, i256 1)
//CHECK-NEXT: %call.fr_mul5 = call i256 @fr_mul(i256 %29, i256 %call.fr_sub4)
//CHECK-NEXT: %call.fr_eq6 = call i1 @fr_eq(i256 %call.fr_mul5, i256 0)
//CHECK-NEXT: call void @__assert(i1 %call.fr_eq6)
//CHECK-NEXT: %constraint7 = alloca i1, align 1
//CHECK-NEXT: call void @__constraint_value(i1 %call.fr_eq6, i1* %constraint7)
//CHECK-NEXT: %32 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 1
//CHECK-NEXT: %33 = load i256, i256* %32, align 4
//CHECK-NEXT: %34 = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 1
//CHECK-NEXT: %35 = load i256, i256* %34, align 4
//CHECK-NEXT: %36 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: %37 = load i256, i256* %36, align 4
//CHECK-NEXT: %call.fr_mul8 = call i256 @fr_mul(i256 %35, i256 %37)
//CHECK-NEXT: %call.fr_add9 = call i256 @fr_add(i256 %33, i256 %call.fr_mul8)
//CHECK-NEXT: %38 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 1
//CHECK-NEXT: store i256 %call.fr_add9, i256* %38, align 4
//CHECK-NEXT: %39 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 2
//CHECK-NEXT: store i256 4, i256* %39, align 4
//CHECK-NEXT: %40 = getelementptr [4 x i256], [4 x i256]* %lvars, i32 0, i32 3
//CHECK-NEXT: store i256 2, i256* %40, align 4

0 comments on commit 5da5ac4

Please sign in to comment.