From 0cf8b2afc7300958a4d9c4d12878fba763417d23 Mon Sep 17 00:00:00 2001 From: Julian Gonzalez Calderon Date: Sun, 18 May 2025 23:26:54 -0300 Subject: [PATCH] cherry: Use dynamic arrays instead of static arrays for circuit data (#1233) --- src/libfuncs/circuit.rs | 308 +++++++++++++++++++---------------- src/types/circuit.rs | 352 +++++++++++++++++++++++++++++++--------- 2 files changed, 441 insertions(+), 219 deletions(-) diff --git a/src/libfuncs/circuit.rs b/src/libfuncs/circuit.rs index 0db7e041b..54ff0cb53 100644 --- a/src/libfuncs/circuit.rs +++ b/src/libfuncs/circuit.rs @@ -6,10 +6,12 @@ use super::{increment_builtin_counter_by, LibfuncHelper}; use crate::{ error::{Result, SierraAssertError}, libfuncs::r#struct::build_struct_value, - metadata::MetadataStorage, + metadata::{ + drop_overrides::DropOverridesMeta, realloc_bindings::ReallocBindingsMeta, MetadataStorage, + }, native_panic, types::{circuit::build_u384_struct_type, TypeBuilder}, - utils::{get_integer_layout, layout_repeat, BlockExt, ProgramRegistryExt}, + utils::{get_integer_layout, layout_repeat, BlockExt, GepIndex, ProgramRegistryExt}, }; use cairo_lang_sierra::{ extensions::{ @@ -28,10 +30,7 @@ use melior::{ arith::{self, CmpiPredicate}, cf, llvm, }, - ir::{ - attribute::DenseI32ArrayAttribute, r#type::IntegerType, Block, BlockLike, Location, Type, - Value, ValueLike, - }, + ir::{r#type::IntegerType, Block, BlockLike, Location, Type, Value, ValueLike}, Context, }; use num_traits::Signed; @@ -106,14 +105,39 @@ fn build_init_circuit_data<'ctx, 'this>( metadata: &mut MetadataStorage, info: &SignatureAndTypeConcreteLibfunc, ) -> Result<()> { - let rc_usage = match registry.get_type(&info.ty)? { - CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => { - info.circuit_info.rc96_usage() - } + let circuit_info = match registry.get_type(&info.ty)? { + CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => &info.circuit_info, _ => return Err(SierraAssertError::BadTypeInfo.into()), }; - let rc = increment_builtin_counter_by(context, entry, location, entry.arg(0)?, rc_usage)?; + let rc = increment_builtin_counter_by( + context, + entry, + location, + entry.arg(0)?, + circuit_info.rc96_usage(), + )?; + + // Calculate full capacity for array. + let capacity = circuit_info.n_inputs; + let u384_layout = get_integer_layout(384); + let capacity_bytes = layout_repeat(&u384_layout, capacity)? + .0 + .pad_to_align() + .size(); + let capacity_bytes_value = entry.const_int(context, location, capacity_bytes, 64)?; + + // Alloc memory for array. + let ptr_ty = llvm::r#type::pointer(context, 0); + let ptr = entry.append_op_result(llvm::zero(ptr_ty, location))?; + let ptr = entry.append_op_result(ReallocBindingsMeta::realloc( + context, + ptr, + capacity_bytes_value, + location, + )?)?; + + // Create accumulator struct. let k0 = entry.const_int(context, location, 0, 64)?; let accumulator_ty = &info.branch_signatures()[0].vars[1].ty; let accumulator = build_struct_value( @@ -124,7 +148,7 @@ fn build_init_circuit_data<'ctx, 'this>( helper, metadata, accumulator_ty, - &[k0], + &[k0, ptr], )?; entry.append_operation(helper.br(0, &[rc, accumulator], location)); @@ -140,16 +164,13 @@ fn build_add_input<'ctx, 'this>( entry: &'this Block<'ctx>, location: Location<'ctx>, helper: &LibfuncHelper<'ctx, 'this>, - metadata: &mut MetadataStorage, + _metadata: &mut MetadataStorage, info: &SignatureAndTypeConcreteLibfunc, ) -> Result<()> { let n_inputs = match registry.get_type(&info.ty)? { CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(info)) => info.circuit_info.n_inputs, _ => return Err(SierraAssertError::BadTypeInfo.into()), }; - let accumulator_type_id = &info.param_signatures()[0].ty; - let accumulator_ctype = registry.get_type(accumulator_type_id)?; - let accumulator_layout = accumulator_ctype.layout(registry)?; let accumulator: Value = entry.arg(0)?; @@ -161,14 +182,42 @@ fn build_add_input<'ctx, 'this>( IntegerType::new(context, 64).into(), 0, )?; + // Calculate next length: next_length = current_length + 1 + let k1 = entry.const_int(context, location, 1, 64)?; + let next_length = entry.addi(current_length, k1, location)?; + // Insert next_length into accumulator + let accumulator = entry.insert_value(context, location, accumulator, next_length, 0)?; + + // Get pointer to inputs array + let inputs_ptr = entry.extract_value( + context, + location, + accumulator, + llvm::r#type::pointer(context, 0), + 1, + )?; + // Get pointer to next input to insert + let next_input_ptr = entry.gep( + context, + location, + inputs_ptr, + &[GepIndex::Value(current_length)], + IntegerType::new(context, 384).into(), + )?; + + // Interpret u384 struct (input) as u384 integer + let u384_struct = entry.arg(1)?; + let new_input = u384_struct_to_integer(context, entry, location, u384_struct)?; + // Store the u384 into next input pointer + entry.store(context, location, next_input_ptr, new_input)?; - // Check if last_insert: current_length == number_of_inputs - 1 - let n_inputs_minus_1 = entry.const_int(context, location, n_inputs - 1, 64)?; + // Check if last_insert: next_length == number_of_inputs + let n_inputs = entry.const_int(context, location, n_inputs, 64)?; let last_insert = entry.cmpi( context, arith::CmpiPredicate::Eq, - current_length, - n_inputs_minus_1, + next_length, + n_inputs, location, )?; @@ -184,124 +233,23 @@ fn build_add_input<'ctx, 'this>( location, )); - // If not last insert, then: + // If not last insert, then return accumulator { - // Calculate next length: next_length = current_length + 1 - let k1 = middle_insert_block.const_int(context, location, 1, 64)?; - let next_length = middle_insert_block.addi(current_length, k1, location)?; - - // Insert next_length into accumulator - let accumulator = - middle_insert_block.insert_value(context, location, accumulator, next_length, 0)?; - - // Get pointer to accumulator with alloc and store - let accumulator_ptr = helper.init_block().alloca1( - context, - location, - accumulator.r#type(), - accumulator_layout.align(), - )?; - middle_insert_block.store(context, location, accumulator_ptr, accumulator)?; - - // Get pointer to next input to insert - let k0 = middle_insert_block.const_int(context, location, 0, 64)?; - let next_input_ptr = - middle_insert_block.append_op_result(llvm::get_element_ptr_dynamic( - context, - accumulator_ptr, - &[k0, k1, current_length], - accumulator.r#type(), - llvm::r#type::pointer(context, 0), - location, - ))?; - - // Interpret u384 struct (input) as u384 integer - let u384_struct = entry.arg(1)?; - let new_input = - u384_struct_to_integer(context, middle_insert_block, location, u384_struct)?; - - // Store the u384 into next input pointer - middle_insert_block.store(context, location, next_input_ptr, new_input)?; - - // Load accumulator from pointer - let accumulator = - middle_insert_block.load(context, location, accumulator_ptr, accumulator.r#type())?; - middle_insert_block.append_operation(helper.br(1, &[accumulator], location)); } - // If is last insert, then: + // If is last insert, then return accumulator.pointer { - let data_type_id = &info.branch_signatures()[0].vars[0].ty; - let (data_type, data_layout) = - registry.build_type_with_layout(context, helper, metadata, data_type_id)?; - - // Alloc return data - let data_ptr = - helper - .init_block() - .alloca1(context, location, data_type, data_layout.align())?; - - // Get pointer to accumulator with alloc and store - let accumulator_ptr = helper.init_block().alloca1( - context, - location, - accumulator.r#type(), - accumulator_layout.align(), - )?; - last_insert_block.store(context, location, accumulator_ptr, accumulator)?; - - // Get pointer to accumulator input - let k0 = last_insert_block.const_int(context, location, 0, 64)?; - let k1 = last_insert_block.const_int(context, location, 1, 64)?; - let accumulator_input_ptr = - last_insert_block.append_op_result(llvm::get_element_ptr_dynamic( - context, - accumulator_ptr, - &[k0, k1], - accumulator.r#type(), - llvm::r#type::pointer(context, 0), - location, - ))?; - - // Copy accumulator input into return data - let accumulator_input_length = last_insert_block.const_int( + // Get pointer to inputs array + let inputs_ptr = last_insert_block.extract_value( context, location, - layout_repeat(&get_integer_layout(384), n_inputs - 1)? - .0 - .size(), - 64, - )?; - last_insert_block.memcpy( - context, - location, - accumulator_input_ptr, - data_ptr, - accumulator_input_length, - ); - - // Interpret u384 struct (input) as u384 integer - let u384_struct = entry.arg(1)?; - let new_input = u384_struct_to_integer(context, last_insert_block, location, u384_struct)?; - - // Get pointer to data end - let data_end_ptr = last_insert_block.append_op_result(llvm::get_element_ptr( - context, - data_ptr, - DenseI32ArrayAttribute::new(context, &[0, n_inputs as i32 - 1]), - data_type, + accumulator, llvm::r#type::pointer(context, 0), - location, - ))?; - - // Store the u384 into next input pointer - last_insert_block.store(context, location, data_end_ptr, new_input)?; - - // Load data from pointer - let data = last_insert_block.load(context, location, data_ptr, data_type)?; + 1, + )?; - last_insert_block.append_operation(helper.br(0, &[data], location)); + last_insert_block.append_operation(helper.br(0, &[inputs_ptr], location)); } Ok(()) @@ -394,6 +342,17 @@ fn build_eval<'ctx, 'this>( // Ok case { + // We drop circuit_data, as its consumed by this libfunc. + if let Some(drop_overrides_meta) = metadata.get::() { + drop_overrides_meta.invoke_override( + context, + ok_block, + location, + &info.signature.param_signatures[3].ty, + circuit_data, + )?; + } + let mul_mod = increment_builtin_counter_by( context, ok_block, @@ -408,12 +367,36 @@ fn build_eval<'ctx, 'this>( .map(|value| u384_integer_to_struct(context, ok_block, location, value)) .collect::>>()?; - let n_gates = circuit_info.values.len(); - let gates_array = ok_block.append_op_result(llvm::undef( - llvm::r#type::array(build_u384_struct_type(context), n_gates as u32), + // Calculate full capacity for array. + let outputs_capacity = circuit_info.values.len(); + let u384_struct_layout = layout_repeat(&get_integer_layout(96), 4)?.0; + let outputs_capacity_bytes = layout_repeat(&u384_struct_layout, outputs_capacity)? + .0 + .pad_to_align() + .size(); + let outputs_capacity_bytes_value = + ok_block.const_int(context, location, outputs_capacity_bytes, 64)?; + + // Alloc memory for array. + let ptr_ty = llvm::r#type::pointer(context, 0); + let outputs_ptr = ok_block.append_op_result(llvm::zero(ptr_ty, location))?; + let outputs_ptr = ok_block.append_op_result(ReallocBindingsMeta::realloc( + context, + outputs_ptr, + outputs_capacity_bytes_value, location, - ))?; - let gates_array = ok_block.insert_values(context, location, gates_array, &gates)?; + )?)?; + + for (i, gate) in gates.into_iter().enumerate() { + let value_ptr = ok_block.gep( + context, + location, + outputs_ptr, + &[GepIndex::Const(i as i32)], + build_u384_struct_type(context), + )?; + ok_block.store(context, location, value_ptr, gate)?; + } let modulus_struct = u384_integer_to_struct(context, ok_block, location, circuit_modulus)?; @@ -427,7 +410,7 @@ fn build_eval<'ctx, 'this>( helper, metadata, outputs_type_id, - &[gates_array, modulus_struct], + &[outputs_ptr, modulus_struct], )?; ok_block.append_operation(helper.br(0, &[add_mod, mul_mod, outputs], location)); @@ -435,6 +418,17 @@ fn build_eval<'ctx, 'this>( // Error case { + // We drop circuit_data, as its consumed by this libfunc. + if let Some(drop_overrides_meta) = metadata.get::() { + drop_overrides_meta.invoke_override( + context, + err_block, + location, + &info.signature.param_signatures[3].ty, + circuit_data, + )?; + } + // We only consider mul gates evaluated before failure let mul_mod = { let mul_mod_usage = err_block.muli( @@ -483,12 +477,18 @@ fn build_gate_evaluation<'ctx, 'this>( let mut values = vec![None; 1 + circuit_info.n_inputs + circuit_info.values.len()]; values[0] = Some(block.const_int(context, location, 1, 384)?); for i in 0..circuit_info.n_inputs { - values[i + 1] = Some(block.extract_value( + let value_ptr = block.gep( context, location, circuit_data, + &[GepIndex::Const(i as i32)], + IntegerType::new(context, 384).into(), + )?; + values[i + 1] = Some(block.load( + context, + location, + value_ptr, IntegerType::new(context, 384).into(), - i, )?); } @@ -880,12 +880,11 @@ fn build_get_output<'ctx, 'this>( let outputs = entry.arg(0)?; - let n_gates = circuit_info.values.len(); - let output_gates = entry.extract_value( + let values_ptr = entry.extract_value( context, location, outputs, - llvm::r#type::array(build_u384_struct_type(context), n_gates as u32), + llvm::r#type::pointer(context, 0), 0, )?; let modulus_struct = entry.extract_value( @@ -895,12 +894,20 @@ fn build_get_output<'ctx, 'this>( build_u384_struct_type(context), 1, )?; - let output_struct = entry.extract_value( + + let output_struct_ptr = entry.gep( + context, + location, + values_ptr, + &[GepIndex::Const(output_idx as i32)], + build_u384_struct_type(context), + )?; + + let output_struct = entry.load( context, location, - output_gates, + output_struct_ptr, build_u384_struct_type(context), - output_idx, )?; let guarantee_type_id = &info.branch_signatures()[0].vars[1].ty; @@ -915,6 +922,21 @@ fn build_get_output<'ctx, 'this>( &[output_struct, modulus_struct], )?; + // We drop the circuit outputs value, as its consumed by this libfunc. + // NOTE: As this libfunc consumes circuit_outputs, this implies that + // calling it multiple times involves duplicating the circuit outputs + // each time. This could be fixed by implementing a reference counter, + // like we do with regular arrays. + if let Some(drop_overrides_meta) = metadata.get::() { + drop_overrides_meta.invoke_override( + context, + entry, + location, + &info.signature.param_signatures[0].ty, + outputs, + )?; + } + entry.append_operation(helper.br(0, &[output_struct, guarantee], location)); Ok(()) diff --git a/src/types/circuit.rs b/src/types/circuit.rs index 613113a40..107506aaf 100644 --- a/src/types/circuit.rs +++ b/src/types/circuit.rs @@ -2,11 +2,14 @@ use std::alloc::Layout; -use super::WithSelf; +use super::{BlockExt, WithSelf}; use crate::{ error::{Result, SierraAssertError}, - metadata::MetadataStorage, - utils::{get_integer_layout, layout_repeat}, + metadata::{ + drop_overrides::DropOverridesMeta, dup_overrides::DupOverridesMeta, + realloc_bindings::ReallocBindingsMeta, MetadataStorage, + }, + utils::{get_integer_layout, layout_repeat, ProgramRegistryExt}, }; use cairo_lang_sierra::{ extensions::{ @@ -18,8 +21,8 @@ use cairo_lang_sierra::{ program_registry::ProgramRegistry, }; use melior::{ - dialect::llvm, - ir::{r#type::IntegerType, Module, Type}, + dialect::{func, llvm}, + ir::{r#type::IntegerType, Block, BlockLike, Location, Module, Region, Type, Value}, Context, }; @@ -88,11 +91,23 @@ pub fn build<'ctx>( } } +/// Builds the circuit accumulator type. +/// +/// ## Layout: +/// +/// Holds up to N_INPUTS elements. Where each element is an u384 integer. +/// +/// ```txt +/// type = struct { +/// size: u64, +/// data: *u384, +/// } +/// ``` pub fn build_circuit_accumulator<'ctx>( context: &'ctx Context, - _module: &Module<'ctx>, + module: &Module<'ctx>, registry: &ProgramRegistry, - _metadata: &mut MetadataStorage, + metadata: &mut MetadataStorage, info: WithSelf, ) -> Result> { let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else { @@ -104,21 +119,95 @@ pub fn build_circuit_accumulator<'ctx>( return Err(SierraAssertError::BadTypeInfo.into()); }; - let n_inputs = circuit.circuit_info.n_inputs; + DupOverridesMeta::register_with( + context, + module, + registry, + metadata, + info.self_ty(), + |metadata| { + let location = Location::unknown(context); + let region = Region::new(); + let value_ty = registry.build_type(context, module, metadata, info.self_ty())?; + let entry = region.append_block(Block::new(&[(value_ty, location)])); + + let accumulator = entry.arg(0)?; + let inputs_ptr = entry.extract_value( + context, + location, + accumulator, + llvm::r#type::pointer(context, 0), + 1, + )?; + + let u384_layout = get_integer_layout(384); + + let new_inputs_ptr = build_array_dup( + context, + &entry, + location, + inputs_ptr, + circuit.circuit_info.n_inputs, + u384_layout, + )?; + + let new_accumulator = + entry.insert_value(context, location, accumulator, new_inputs_ptr, 1)?; + entry.append_operation(func::r#return(&[accumulator, new_accumulator], location)); + + Ok(Some(region)) + }, + )?; + DropOverridesMeta::register_with( + context, + module, + registry, + metadata, + info.self_ty(), + |metadata| { + let location = Location::unknown(context); + let region = Region::new(); + let value_ty = registry.build_type(context, module, metadata, info.self_ty())?; + let entry = region.append_block(Block::new(&[(value_ty, location)])); + + let accumulator = entry.arg(0)?; + let inputs_ptr = entry.extract_value( + context, + location, + accumulator, + llvm::r#type::pointer(context, 0), + 1, + )?; + + entry.append_operation(ReallocBindingsMeta::free(context, inputs_ptr, location)?); + entry.append_operation(func::r#return(&[], location)); + + Ok(Some(region)) + }, + )?; let fields = vec![ IntegerType::new(context, 64).into(), - llvm::r#type::array(IntegerType::new(context, 384).into(), n_inputs as u32 - 1), + llvm::r#type::pointer(context, 0), ]; Ok(llvm::r#type::r#struct(context, &fields, false)) } +/// Builds the circuit data type. +/// +/// ## Layout: +/// +/// Holds N_INPUTS elements. Where each element is an u384. +/// +/// ```txt +/// type = *u384 +/// ``` pub fn build_circuit_data<'ctx>( context: &'ctx Context, - _module: &Module<'ctx>, + module: &Module<'ctx>, registry: &ProgramRegistry, - _metadata: &mut MetadataStorage, + metadata: &mut MetadataStorage, info: WithSelf, ) -> Result> { let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else { @@ -130,19 +219,85 @@ pub fn build_circuit_data<'ctx>( return Err(SierraAssertError::BadTypeInfo.into()); }; - let n_inputs = circuit.circuit_info.n_inputs; + DupOverridesMeta::register_with( + context, + module, + registry, + metadata, + info.self_ty(), + |metadata| { + let location = Location::unknown(context); + let region = Region::new(); + let value_ty = registry.build_type(context, module, metadata, info.self_ty())?; + let entry = region.append_block(Block::new(&[(value_ty, location)])); + + let data_ptr = entry.arg(0)?; - Ok(llvm::r#type::array( - IntegerType::new(context, 384).into(), - n_inputs as u32, - )) + let u384_layout = get_integer_layout(384); + + let new_data_ptr = build_array_dup( + context, + &entry, + location, + data_ptr, + circuit.circuit_info.n_inputs, + u384_layout, + )?; + + entry.append_operation(func::r#return(&[data_ptr, new_data_ptr], location)); + + Ok(Some(region)) + }, + )?; + DropOverridesMeta::register_with( + context, + module, + registry, + metadata, + info.self_ty(), + |metadata| { + let location = Location::unknown(context); + let region = Region::new(); + let value_ty = registry.build_type(context, module, metadata, info.self_ty())?; + let entry = region.append_block(Block::new(&[(value_ty, location)])); + + let data_ptr = entry.arg(0)?; + + entry.append_operation(ReallocBindingsMeta::free(context, data_ptr, location)?); + entry.append_operation(func::r#return(&[], location)); + + Ok(Some(region)) + }, + )?; + + Ok(llvm::r#type::pointer(context, 0)) } +/// Builds the circuit outputs type. +/// +/// ## Layout: +/// +/// Holds N_VALUES elements, where each element is a u384 struct, +/// A u384 struct contains 4 limbs, each a u96 integer. +/// +/// ```txt +/// type = struct { +/// data: *u384s, +/// modulus: u384s, +/// }; +/// +/// u384s = struct { +/// limb1: u96, +/// limb2: u96, +/// limb3: u96, +/// limb4: u96, +/// } +/// ``` pub fn build_circuit_outputs<'ctx>( context: &'ctx Context, - _module: &Module<'ctx>, + module: &Module<'ctx>, registry: &ProgramRegistry, - _metadata: &mut MetadataStorage, + metadata: &mut MetadataStorage, info: WithSelf, ) -> Result> { let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() else { @@ -154,12 +309,76 @@ pub fn build_circuit_outputs<'ctx>( return Err(SierraAssertError::BadTypeInfo.into()); }; - let n_gates = circuit.circuit_info.values.len(); + DupOverridesMeta::register_with( + context, + module, + registry, + metadata, + info.self_ty(), + |metadata| { + let location = Location::unknown(context); + let region = Region::new(); + let value_ty = registry.build_type(context, module, metadata, info.self_ty())?; + let entry = region.append_block(Block::new(&[(value_ty, location)])); + + let outputs = entry.arg(0)?; + let gates_ptr = entry.extract_value( + context, + location, + outputs, + llvm::r#type::pointer(context, 0), + 0, + )?; + + let u384_struct_layout = layout_repeat(&get_integer_layout(96), 4)?.0; + + let new_gates_ptr = build_array_dup( + context, + &entry, + location, + gates_ptr, + circuit.circuit_info.values.len(), + u384_struct_layout, + )?; + + let new_outputs = entry.insert_value(context, location, outputs, new_gates_ptr, 0)?; + entry.append_operation(func::r#return(&[outputs, new_outputs], location)); + + Ok(Some(region)) + }, + )?; + DropOverridesMeta::register_with( + context, + module, + registry, + metadata, + info.self_ty(), + |metadata| { + let location = Location::unknown(context); + let region = Region::new(); + let value_ty = registry.build_type(context, module, metadata, info.self_ty())?; + let entry = region.append_block(Block::new(&[(value_ty, location)])); + + let outputs = entry.arg(0)?; + let gates_ptr = entry.extract_value( + context, + location, + outputs, + llvm::r#type::pointer(context, 0), + 0, + )?; + + entry.append_operation(ReallocBindingsMeta::free(context, gates_ptr, location)?); + entry.append_operation(func::r#return(&[], location)); + + Ok(Some(region)) + }, + )?; Ok(llvm::r#type::r#struct( context, &[ - llvm::r#type::array(build_u384_struct_type(context), n_gates as u32), + llvm::r#type::pointer(context, 0), build_u384_struct_type(context), ], false, @@ -185,6 +404,33 @@ pub fn build_u96_limbs_less_than_guarantee<'ctx>( )) } +pub fn build_array_dup<'ctx, 'this>( + context: &'ctx Context, + block: &'this Block<'ctx>, + location: Location<'ctx>, + ptr: Value<'ctx, 'this>, + capacity: usize, + layout: Layout, +) -> Result> { + let capacity_bytes = layout_repeat(&layout, capacity)?.0.pad_to_align().size(); + let capacity_bytes_value = block.const_int(context, location, capacity_bytes, 64)?; + + let new_inputs_ptr = { + let ptr_ty = llvm::r#type::pointer(context, 0); + let new_inputs_ptr = block.append_op_result(llvm::zero(ptr_ty, location))?; + block.append_op_result(ReallocBindingsMeta::realloc( + context, + new_inputs_ptr, + capacity_bytes_value, + location, + )?)? + }; + + block.memcpy(context, location, ptr, new_inputs_ptr, capacity_bytes_value); + + Ok(new_inputs_ptr) +} + pub const fn is_complex(info: &CircuitTypeConcrete) -> bool { match *info { CircuitTypeConcrete::AddMod(_) @@ -232,7 +478,7 @@ pub const fn is_zst(info: &CircuitTypeConcrete) -> bool { } pub fn layout( - registry: &ProgramRegistry, + _registry: &ProgramRegistry, info: &CircuitTypeConcrete, ) -> Result { match info { @@ -252,64 +498,18 @@ pub fn layout( | CircuitTypeConcrete::CircuitDescriptor(_) | CircuitTypeConcrete::CircuitFailureGuarantee(_) => Ok(Layout::new::<()>()), - CircuitTypeConcrete::CircuitData(info) => { - let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() - else { - return Err(SierraAssertError::BadTypeInfo.into()); - }; - let CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(circuit)) = - registry.get_type(circuit_type_id)? - else { - return Err(SierraAssertError::BadTypeInfo.into()); - }; - - let n_inputs = circuit.circuit_info.n_inputs; + CircuitTypeConcrete::CircuitData(_) => Ok(Layout::new::<*mut ()>()), + CircuitTypeConcrete::CircuitOutputs(_) => { + let u384_struct_layout = layout_repeat(&get_integer_layout(96), 4)?.0; + let pointer_layout = Layout::new::<*mut ()>(); - let u384_layout = get_integer_layout(384); - - let layout = layout_repeat(&u384_layout, n_inputs)?.0; - - Ok(layout) + Ok(pointer_layout.extend(u384_struct_layout)?.0) } - CircuitTypeConcrete::CircuitOutputs(info) => { - let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() - else { - return Err(SierraAssertError::BadTypeInfo.into()); - }; - let CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(circuit)) = - registry.get_type(circuit_type_id)? - else { - return Err(SierraAssertError::BadTypeInfo.into()); - }; - - let n_gates = circuit.circuit_info.values.len(); - - let u384_layout = get_integer_layout(384); - - let layout = layout_repeat(&u384_layout, n_gates)?.0; - - Ok(layout) - } - CircuitTypeConcrete::CircuitInputAccumulator(info) => { - let Some(GenericArg::Type(circuit_type_id)) = info.info.long_id.generic_args.first() - else { - return Err(SierraAssertError::BadTypeInfo.into()); - }; - let CoreTypeConcrete::Circuit(CircuitTypeConcrete::Circuit(circuit)) = - registry.get_type(circuit_type_id)? - else { - return Err(SierraAssertError::BadTypeInfo.into()); - }; - - let n_inputs = circuit.circuit_info.n_inputs; - - let length_layout = get_integer_layout(64); - - let u384_layout = get_integer_layout(384); - let inputs_layout = layout_repeat(&u384_layout, n_inputs - 1)?.0; - let layout = length_layout.extend(inputs_layout)?.0; + CircuitTypeConcrete::CircuitInputAccumulator(_) => { + let integer_layout = get_integer_layout(64); + let pointer_layout = Layout::new::<*mut ()>(); - Ok(layout) + Ok(integer_layout.extend(pointer_layout)?.0) } CircuitTypeConcrete::CircuitPartialOutputs(_) => Ok(Layout::new::<()>()), }