Skip to content

Commit

Permalink
More solid approach to generating the pointers and fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
0xddom committed Oct 18, 2023
1 parent 95b981d commit 79f1513
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 19 deletions.
53 changes: 53 additions & 0 deletions circom/tests/arrays/array_copy1.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
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 A(n) {
signal input inp[n];
signal output out[n];

out <== inp;
}

component main = A(5);

//CHECK-LABEL: define void @A_{{[0-9]+}}_run
//CHECK-SAME: ([0 x i256]* %0)
//CHECK: %[[INP_PTR:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK: %[[INP_PTR_DST:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 5
//CHECK: call void @fr_copy_n(i256* %[[INP_PTR_DST]], i256* %[[INP_PTR]], i32 5)

//CHECK: %[[INP_PTR_0:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 5
//CHECK: %[[INP_PTR_DST_0:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK: %[[INP_0:[0-9]+]] = load i256, i256* %[[INP_PTR_0]]
//CHECK: %[[INP_DST_0:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_0]]
//CHECK: %constraint_0 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_0]], i256 %[[INP_DST_0]], i1* %constraint_0)

//CHECK: %[[INP_PTR_1:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 6
//CHECK: %[[INP_PTR_DST_1:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 1
//CHECK: %[[INP_1:[0-9]+]] = load i256, i256* %[[INP_PTR_1]]
//CHECK: %[[INP_DST_1:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_1]]
//CHECK: %constraint_1 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_1]], i256 %[[INP_DST_1]], i1* %constraint_1)

//CHECK: %[[INP_PTR_2:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 7
//CHECK: %[[INP_PTR_DST_2:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 2
//CHECK: %[[INP_2:[0-9]+]] = load i256, i256* %[[INP_PTR_2]]
//CHECK: %[[INP_DST_2:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_2]]
//CHECK: %constraint_2 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_2]], i256 %[[INP_DST_2]], i1* %constraint_2)

//CHECK: %[[INP_PTR_3:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 8
//CHECK: %[[INP_PTR_DST_3:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 3
//CHECK: %[[INP_3:[0-9]+]] = load i256, i256* %[[INP_PTR_3]]
//CHECK: %[[INP_DST_3:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_3]]
//CHECK: %constraint_3 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_3]], i256 %[[INP_DST_3]], i1* %constraint_3)

//CHECK: %[[INP_PTR_4:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 9
//CHECK: %[[INP_PTR_DST_4:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 4
//CHECK: %[[INP_4:[0-9]+]] = load i256, i256* %[[INP_PTR_4]]
//CHECK: %[[INP_DST_4:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_4]]
//CHECK: %constraint_4 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_4]], i256 %[[INP_DST_4]], i1* %constraint_4)
52 changes: 52 additions & 0 deletions circom/tests/arrays/array_copy2.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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 A(n, S) {
signal output out[n];

out <== S;
}

component main = A(5, [11,22,33,44,55]);

//CHECK-LABEL: define void @A_{{[0-9]+}}_run
//CHECK-SAME: ([0 x i256]* %0)
//CHECK: %[[INP_PTR:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK: %[[INP_PTR_DST:[0-9]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 0
//CHECK: call void @fr_copy_n(i256* %[[INP_PTR_DST]], i256* %[[INP_PTR]], i32 5)

//CHECK: %[[INP_PTR_0:[0-9]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 0
//CHECK: %[[INP_PTR_DST_0:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK: %[[INP_0:[0-9]+]] = load i256, i256* %[[INP_PTR_0]]
//CHECK: %[[INP_DST_0:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_0]]
//CHECK: %constraint_0 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_0]], i256 %[[INP_DST_0]], i1* %constraint_0)

//CHECK: %[[INP_PTR_1:[0-9]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 1
//CHECK: %[[INP_PTR_DST_1:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 1
//CHECK: %[[INP_1:[0-9]+]] = load i256, i256* %[[INP_PTR_1]]
//CHECK: %[[INP_DST_1:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_1]]
//CHECK: %constraint_1 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_1]], i256 %[[INP_DST_1]], i1* %constraint_1)

//CHECK: %[[INP_PTR_2:[0-9]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 2
//CHECK: %[[INP_PTR_DST_2:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 2
//CHECK: %[[INP_2:[0-9]+]] = load i256, i256* %[[INP_PTR_2]]
//CHECK: %[[INP_DST_2:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_2]]
//CHECK: %constraint_2 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_2]], i256 %[[INP_DST_2]], i1* %constraint_2)

//CHECK: %[[INP_PTR_3:[0-9]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 3
//CHECK: %[[INP_PTR_DST_3:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 3
//CHECK: %[[INP_3:[0-9]+]] = load i256, i256* %[[INP_PTR_3]]
//CHECK: %[[INP_DST_3:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_3]]
//CHECK: %constraint_3 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_3]], i256 %[[INP_DST_3]], i1* %constraint_3)

//CHECK: %[[INP_PTR_4:[0-9]+]] = getelementptr [6 x i256], [6 x i256]* %lvars, i32 0, i32 4
//CHECK: %[[INP_PTR_DST_4:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 4
//CHECK: %[[INP_4:[0-9]+]] = load i256, i256* %[[INP_PTR_4]]
//CHECK: %[[INP_DST_4:[0-9]+]] = load i256, i256* %[[INP_PTR_DST_4]]
//CHECK: %constraint_4 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_4]], i256 %[[INP_DST_4]], i1* %constraint_4)
20 changes: 10 additions & 10 deletions circom/tests/subcmps/array_copy_constraints.circom
Original file line number Diff line number Diff line change
Expand Up @@ -37,37 +37,37 @@ component main = Caller(5);
//CHECK: %decrement.counter = sub i32 %load.subcmp.counter, 5
//CHECK: call void @Sum_{{[0-9]+}}_run([0 x i256]* %{{[0-9]+}})

//CHECK: %[[INP_PTR_0:[0-9]+]] = getelementptr i256, i256* %[[INP_PTR]], i32 0
//CHECK: %[[INP_PTR_0:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 0
//CHECK: %[[SUBCMP_INP_PTR_0:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %[[SUBCMP_INP_ARR]], i32 0, i32 1
//CHECK: %[[INP_0:[0-9]+]] = load i256, i256* %[[INP_PTR_0]]
//CHECK: %[[SUBCMP_INP_PTR_0:[0-9]+]] = getelementptr i256, i256* %[[SUBCMP_INP_PTR]], i32 0
//CHECK: %[[SUBCMP_INP_0:[0-9]+]] = load i256, i256* %[[SUBCMP_INP_PTR_0]]
//CHECK: %constraint_0 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_0]], i256 %[[SUBCMP_INP_0]], i1* %constraint_0)

//CHECK: %[[INP_PTR_1:[0-9]+]] = getelementptr i256, i256* %[[INP_PTR]], i32 1
//CHECK: %[[INP_PTR_1:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 1
//CHECK: %[[SUBCMP_INP_PTR_1:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %[[SUBCMP_INP_ARR]], i32 0, i32 2
//CHECK: %[[INP_1:[0-9]+]] = load i256, i256* %[[INP_PTR_1]]
//CHECK: %[[SUBCMP_INP_PTR_1:[0-9]+]] = getelementptr i256, i256* %[[SUBCMP_INP_PTR]], i32 1
//CHECK: %[[SUBCMP_INP_1:[0-9]+]] = load i256, i256* %[[SUBCMP_INP_PTR_1]]
//CHECK: %constraint_1 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_1]], i256 %[[SUBCMP_INP_1]], i1* %constraint_1)

//CHECK: %[[INP_PTR_2:[0-9]+]] = getelementptr i256, i256* %[[INP_PTR]], i32 2
//CHECK: %[[INP_PTR_2:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 2
//CHECK: %[[SUBCMP_INP_PTR_2:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %[[SUBCMP_INP_ARR]], i32 0, i32 3
//CHECK: %[[INP_2:[0-9]+]] = load i256, i256* %[[INP_PTR_2]]
//CHECK: %[[SUBCMP_INP_PTR_2:[0-9]+]] = getelementptr i256, i256* %[[SUBCMP_INP_PTR]], i32 2
//CHECK: %[[SUBCMP_INP_2:[0-9]+]] = load i256, i256* %[[SUBCMP_INP_PTR_2]]
//CHECK: %constraint_2 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_2]], i256 %[[SUBCMP_INP_2]], i1* %constraint_2)

//CHECK: %[[INP_PTR_3:[0-9]+]] = getelementptr i256, i256* %[[INP_PTR]], i32 3
//CHECK: %[[INP_PTR_3:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 3
//CHECK: %[[SUBCMP_INP_PTR_3:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %[[SUBCMP_INP_ARR]], i32 0, i32 4
//CHECK: %[[INP_3:[0-9]+]] = load i256, i256* %[[INP_PTR_3]]
//CHECK: %[[SUBCMP_INP_PTR_3:[0-9]+]] = getelementptr i256, i256* %[[SUBCMP_INP_PTR]], i32 3
//CHECK: %[[SUBCMP_INP_3:[0-9]+]] = load i256, i256* %[[SUBCMP_INP_PTR_3]]
//CHECK: %constraint_3 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_3]], i256 %[[SUBCMP_INP_3]], i1* %constraint_3)

//CHECK: %[[INP_PTR_4:[0-9]+]] = getelementptr i256, i256* %[[INP_PTR]], i32 4
//CHECK: %[[INP_PTR_4:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %0, i32 0, i32 4
//CHECK: %[[SUBCMP_INP_PTR_4:[0-9]+]] = getelementptr [0 x i256], [0 x i256]* %[[SUBCMP_INP_ARR]], i32 0, i32 5
//CHECK: %[[INP_4:[0-9]+]] = load i256, i256* %[[INP_PTR_4]]
//CHECK: %[[SUBCMP_INP_PTR_4:[0-9]+]] = getelementptr i256, i256* %[[SUBCMP_INP_PTR]], i32 4
//CHECK: %[[SUBCMP_INP_4:[0-9]+]] = load i256, i256* %[[SUBCMP_INP_PTR_4]]
//CHECK: %constraint_4 = alloca i1
//CHECK: call void @__constraint_values(i256 %[[INP_4]], i256 %[[SUBCMP_INP_4]], i1* %constraint_4)
17 changes: 14 additions & 3 deletions code_producers/src/llvm_elements/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::llvm_elements::{LLVMIRProducer};
use crate::llvm_elements::fr::{FR_MUL_FN_NAME, FR_LT_FN_NAME};
use crate::llvm_elements::functions::create_bb;
use crate::llvm_elements::types::{bigint_type, i32_type};
use crate::llvm_elements::values::zero;

use super::types::bool_type;

Expand Down Expand Up @@ -861,9 +862,19 @@ pub fn create_switch<'a>(
producer.builder().build_switch(value, else_block, cases)
}

pub fn get_index_from_gep(gep: PointerValue) -> usize {
/// Extracts the pointer and the second index of a gep instruction
/// getelementptr %ptr, 0, %idx ---> (%ptr, %idx)
pub fn get_data_from_gep<'a>(producer: &dyn LLVMIRProducer<'a>, gep: PointerValue<'a>) -> (PointerValue<'a>, usize) {
let inst = gep.as_instruction().expect("GEP has to be an instruction!");
assert!(inst.get_opcode() == InstructionOpcode::GetElementPtr);
debug_assert!(inst.get_opcode() == InstructionOpcode::GetElementPtr);
let ptr = inst.get_operand(0)
.expect("Pointer is missing in GEP")
.expect_left("Pointer value must be a basic value!")
.into_pointer_value();
let fst_idx = inst.get_operand(1)
.expect("First index is missing in GEP")
.expect_left("First index must be a basic value!");
debug_assert!(fst_idx == zero(producer));
let op = inst.get_operand(2);
let idx = op
.expect("Second index is missing in GEP that is meant to be a signal")
Expand All @@ -872,5 +883,5 @@ pub fn get_index_from_gep(gep: PointerValue) -> usize {
BasicValueEnum::IntValue(v) => v.get_sign_extended_constant(),
_ => panic!("Second index must be an integer value!")
};
n.expect("Could not load the integer value of the IntValue!") as usize
(ptr, n.expect("Could not load the integer value of the IntValue!") as usize)
}
14 changes: 8 additions & 6 deletions compiler/src/intermediate_representation/constraint_bucket.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use code_producers::c_elements::CProducer;
use code_producers::llvm_elements::types::bigint_type;
use code_producers::llvm_elements::values::create_literal_u32;
use code_producers::llvm_elements::values::{create_literal_u32, zero};
use code_producers::llvm_elements::{
LLVMInstruction, new_constraint, to_basic_metadata_enum, LLVMIRProducer, AnyType, new_constraint_with_name,
};
use code_producers::llvm_elements::instructions::{create_call, create_load, get_instruction_arg, get_index_from_gep};
use code_producers::llvm_elements::instructions::{create_call, create_load, get_instruction_arg, get_data_from_gep, create_gep};
use code_producers::llvm_elements::stdlib::{CONSTRAINT_VALUE_FN_NAME, CONSTRAINT_VALUES_FN_NAME};
use code_producers::wasm_elements::WASMProducer;
use crate::intermediate_representation::{Instruction, InstructionPointer, SExp, ToSExp, UpdateId};
Expand Down Expand Up @@ -150,11 +150,13 @@ impl WriteLLVMIR for ConstraintBucket {
assert_eq!(bigint_type(producer).ptr_type(Default::default()), lhs_ptr.get_type(), "wrong type");
let rhs_ptr = get_instruction_arg(prev.into_instruction_value(), STORE_SRC_IDX).into_pointer_value();
let mut last_call = None;
let lhs_base_off = get_index_from_gep(lhs_ptr);
let rhs_base_off = get_index_from_gep(rhs_ptr);
let (lhs_ptr, lhs_base_off) = get_data_from_gep(producer, lhs_ptr);
let (rhs_ptr, rhs_base_off) = get_data_from_gep(producer, rhs_ptr);
for i in 0..size {
let lhs_gep = producer.template_ctx().get_signal(producer, create_literal_u32(producer, (lhs_base_off + i) as u64));
let rhs_gep = producer.template_ctx().get_signal(producer, create_literal_u32(producer, (rhs_base_off + i) as u64));
let lhs_idx = create_literal_u32(producer, (lhs_base_off + i) as u64);
let rhs_idx = create_literal_u32(producer, (rhs_base_off + i) as u64);
let lhs_gep = create_gep(producer, lhs_ptr, &[zero(producer), lhs_idx]);
let rhs_gep = create_gep(producer, rhs_ptr, &[zero(producer), rhs_idx]);
let lhs = create_load(producer, lhs_gep.into_pointer_value());
let rhs = create_load(producer, rhs_gep.into_pointer_value());
let constr = new_constraint_with_name(producer, format!("constraint_{}", i).as_str());
Expand Down

0 comments on commit 79f1513

Please sign in to comment.