From 2cb7501104d0e3cda2dee6cf77f9f290f9b29393 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Thu, 13 Feb 2025 11:04:11 +0100 Subject: [PATCH 01/14] Partial array refactor. --- src/libfuncs/array.rs | 2650 +++++++++++++++++------------------------ src/types.rs | 2 +- src/types/array.rs | 58 +- src/values.rs | 34 +- 4 files changed, 1181 insertions(+), 1563 deletions(-) diff --git a/src/libfuncs/array.rs b/src/libfuncs/array.rs index 43782a3f5..453dd42e6 100644 --- a/src/libfuncs/array.rs +++ b/src/libfuncs/array.rs @@ -7,6 +7,7 @@ use crate::{ drop_overrides::DropOverridesMeta, dup_overrides::DupOverridesMeta, realloc_bindings::ReallocBindingsMeta, MetadataStorage, }, + types::array::calc_data_prefix_offset, utils::{get_integer_layout, BlockExt, GepIndex, ProgramRegistryExt}, }; use cairo_lang_sierra::{ @@ -54,73 +55,94 @@ pub fn build<'ctx, 'this>( ArrayConcreteLibfunc::Append(info) => { build_append(context, registry, entry, location, helper, metadata, info) } - ArrayConcreteLibfunc::PopFront(info) => build_pop::( - context, - registry, - entry, - location, - helper, - metadata, - PopInfo::Single(info), - ), - ArrayConcreteLibfunc::PopFrontConsume(info) => build_pop::( - context, - registry, - entry, - location, - helper, - metadata, - PopInfo::Single(info), - ), + ArrayConcreteLibfunc::PopFront(info) => { + // build_pop::( + // context, + // registry, + // entry, + // location, + // helper, + // metadata, + // PopInfo::Single(info), + // ) + todo!() + } + ArrayConcreteLibfunc::PopFrontConsume(info) => { + // build_pop::( + // context, + // registry, + // entry, + // location, + // helper, + // metadata, + // PopInfo::Single(info), + // ) + todo!() + } ArrayConcreteLibfunc::Get(info) => { - build_get(context, registry, entry, location, helper, metadata, info) + // build_get(context, registry, entry, location, helper, metadata, info) + todo!() } ArrayConcreteLibfunc::Slice(info) => { - build_slice(context, registry, entry, location, helper, metadata, info) + // build_slice(context, registry, entry, location, helper, metadata, info) + todo!() } ArrayConcreteLibfunc::Len(info) => { - build_len(context, registry, entry, location, helper, metadata, info) + // build_len(context, registry, entry, location, helper, metadata, info) + todo!() + } + ArrayConcreteLibfunc::SnapshotPopFront(info) => { + // build_pop::( + // context, + // registry, + // entry, + // location, + // helper, + // metadata, + // PopInfo::Single(info), + // ) + todo!() + } + ArrayConcreteLibfunc::SnapshotPopBack(info) => { + // build_pop::( + // context, + // registry, + // entry, + // location, + // helper, + // metadata, + // PopInfo::Single(info), + // ), + todo!() + } + ArrayConcreteLibfunc::SnapshotMultiPopFront(info) => { + // build_pop::( + // context, + // registry, + // entry, + // location, + // helper, + // metadata, + // PopInfo::Multi(info), + // ), + todo!() + } + ArrayConcreteLibfunc::SnapshotMultiPopBack(info) => { + // build_pop::( + // context, + // registry, + // entry, + // location, + // helper, + // metadata, + // PopInfo::Multi(info), + // ), + todo!() } - ArrayConcreteLibfunc::SnapshotPopFront(info) => build_pop::( - context, - registry, - entry, - location, - helper, - metadata, - PopInfo::Single(info), - ), - ArrayConcreteLibfunc::SnapshotPopBack(info) => build_pop::( - context, - registry, - entry, - location, - helper, - metadata, - PopInfo::Single(info), - ), - ArrayConcreteLibfunc::SnapshotMultiPopFront(info) => build_pop::( - context, - registry, - entry, - location, - helper, - metadata, - PopInfo::Multi(info), - ), - ArrayConcreteLibfunc::SnapshotMultiPopBack(info) => build_pop::( - context, - registry, - entry, - location, - helper, - metadata, - PopInfo::Multi(info), - ), } } -/// Buils a new array with no initial capacity +/// Builds a new array with no initial capacity. /// /// # Cairo Signature /// @@ -152,14 +174,16 @@ pub fn build_new<'ctx, 'this>( Ok(()) } -/// Buils a span (a cairo native array) from a box of a tuple (struct with elements of the same type) +/// Buils a span (a cairo native array) from a boxed tuple of same-type elements. /// /// Note: The `&info.ty` field has the entire `[T; N]` tuple. It is not the `T` in `Array`. /// /// # Cairo Signature /// /// ```cairo -/// extern fn span_from_tuple>(struct_like: Box<@T>) -> @Array nopanic; +/// extern fn span_from_tuple>( +/// struct_like: Box<@T> +/// ) -> @Array nopanic; /// ``` pub fn build_span_from_tuple<'ctx, 'this>( context: &'ctx Context, @@ -188,7 +212,7 @@ pub fn build_span_from_tuple<'ctx, 'this>( let array_len_bytes_with_offset = entry.const_int( context, location, - array_len_bytes + calc_refcount_offset(tuple_layout), + array_len_bytes + calc_data_prefix_offset(tuple_layout), 64, )?; let array_len_bytes = entry.const_int(context, location, array_len_bytes, 64)?; @@ -197,7 +221,7 @@ pub fn build_span_from_tuple<'ctx, 'this>( let k0 = entry.const_int_from_type(context, location, 0, len_ty)?; let k1 = entry.const_int_from_type(context, location, 1, len_ty)?; - // build the new span (array) + // Allocate space for the array. let allocation_ptr = entry.append_op_result(llvm::zero(ptr_ty, location))?; let allocation_ptr = entry.append_op_result(ReallocBindingsMeta::realloc( context, @@ -205,17 +229,24 @@ pub fn build_span_from_tuple<'ctx, 'this>( array_len_bytes_with_offset, location, )?)?; - entry.store(context, location, allocation_ptr, k1)?; + + // Write the array data prefix. + let data_prefix = entry.append_op_result(llvm::undef( + llvm::r#type::r#struct(context, &[], false), + location, + ))?; + let data_prefix = entry.insert_values(context, location, data_prefix, &[k1, array_len])?; + entry.store(context, location, allocation_ptr, data_prefix)?; let array_ptr = entry.gep( context, location, allocation_ptr, - &[GepIndex::Const(calc_refcount_offset(tuple_layout) as i32)], + &[GepIndex::Const(calc_data_prefix_offset(tuple_layout) as i32)], IntegerType::new(context, 8).into(), )?; - // as a tuple has the same representation as the array data, - // we just memcpy into the new array. + // Move the data into the array and free the original tuple. Since the tuple and the array are + // represented the same way, a simple memcpy is enough. entry.memcpy( context, location, @@ -229,6 +260,18 @@ pub fn build_span_from_tuple<'ctx, 'this>( location, )?); + // Build the array representation. + let k8 = entry.const_int(context, location, 8, 64)?; + let array_ptr_ptr = + entry.append_op_result(llvm::zero(llvm::r#type::pointer(context, 0), location))?; + let array_ptr_ptr: Value<'ctx, '_> = entry.append_op_result(ReallocBindingsMeta::realloc( + context, + array_ptr_ptr, + k8, + location, + )?)?; + entry.store(context, location, array_ptr_ptr, array_ptr)?; + let value = entry.append_op_result(llvm::undef( llvm::r#type::r#struct(context, &[ptr_ty, len_ty, len_ty, len_ty], false), location, @@ -237,7 +280,7 @@ pub fn build_span_from_tuple<'ctx, 'this>( context, location, value, - &[array_ptr, k0, array_len, array_len], + &[array_ptr_ptr, k0, array_len, array_len], )?; entry.append_operation(helper.br(0, &[value], location)); @@ -291,7 +334,8 @@ pub fn build_tuple_from_span<'ctx, 'this>( let (tuple_ty, tuple_layout) = registry.build_type_with_layout(context, helper, metadata, &info.ty)?; - let array_ptr = entry.extract_value(context, location, entry.argument(0)?.into(), ptr_ty, 0)?; + let array_ptr_ptr = + entry.extract_value(context, location, entry.argument(0)?.into(), ptr_ty, 0)?; let array_start = entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 1)?; let array_end = entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 2)?; @@ -306,7 +350,7 @@ pub fn build_tuple_from_span<'ctx, 'this>( location, ))?; - // check if the expected tuple matches the array length + // Ensure the tuple's length matches the array's. let valid_block = helper.append_block(Block::new(&[])); let error_block = helper.append_block(Block::new(&[])); entry.append_operation(cf::cond_br( @@ -327,9 +371,8 @@ pub fn build_tuple_from_span<'ctx, 'this>( &info.signature.param_signatures[0].ty, )?; + // Branch for when the lengths match: { - // if the length matches... - let value_size = valid_block.const_int(context, location, tuple_layout.size(), 64)?; let value = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; @@ -337,9 +380,6 @@ pub fn build_tuple_from_span<'ctx, 'this>( context, value, value_size, location, )?)?; - // check if the array is shared - let is_shared = is_shared(context, valid_block, location, array_ptr, elem_layout)?; - let array_start_offset = valid_block.append_op_result(arith::extui( array_start, IntegerType::new(context, 64).into(), @@ -350,6 +390,8 @@ pub fn build_tuple_from_span<'ctx, 'this>( valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?, location, ))?; + + let array_ptr = valid_block.load(context, location, array_ptr_ptr, ptr_ty)?; let array_data_start_ptr = valid_block.gep( context, location, @@ -358,13 +400,13 @@ pub fn build_tuple_from_span<'ctx, 'this>( IntegerType::new(context, 8).into(), )?; + // Check if the array is shared. + let is_shared = is_shared(context, valid_block, location, array_ptr_ptr, elem_layout)?; valid_block.append_operation(scf::r#if( is_shared, &[], { - // if the array is shared we clone the inner data, - // as a tuple does not contain a reference counter. - + // When the array is shared, we should clone the entire data. let region = Region::new(); let block = region.append_block(Block::new(&[])); @@ -375,8 +417,8 @@ pub fn build_tuple_from_span<'ctx, 'this>( let value = block.load(context, location, src_ptr, tuple_ty)?; - // as the array data has the same representation as the tuple, - // we can use the tuple override, which is simpler. + // Invoke the tuple's clone mechanism, which will take care of copying or + // cloning each item in the array. let values = dup_overrides_meta .invoke_override(context, &block, location, &info.ty, value)?; block.store(context, location, src_ptr, values.0)?; @@ -385,7 +427,7 @@ pub fn build_tuple_from_span<'ctx, 'this>( _ => block.memcpy(context, location, array_data_start_ptr, value, value_size), } - // drop the original array (decreasing its reference counter) + // Drop the original array (by decreasing its reference counter). metadata .get::() .to_native_assert_error("array always has a drop implementation")? @@ -401,28 +443,32 @@ pub fn build_tuple_from_span<'ctx, 'this>( region }, { - // if the array is not shared, then move the data to the new tuple - // and manually free the allocation (without calling drop on its elements). + // When the array is not shared, we can just move the data to the new tuple and free + // the array. let region = Region::new(); let block = region.append_block(Block::new(&[])); block.memcpy(context, location, array_data_start_ptr, value, value_size); - // NOTE: If the target tuple has no elements, and the array is not shared, - // then we will attempt to free 0xfffffffffffffff0. This is not possible and - // disallowed by the cairo compiler. + // NOTE: If the target tuple has no elements, and the array is not shared, then we + // would attempt to free 0xfffffffffffffff0. This is not possible and disallowed by + // the Cairo compiler. - let array_allocation_ptr = block.gep( + // TODO: Drop elements before array_start and between array_end and max length. + let data_ptr = block.gep( context, location, array_ptr, - &[GepIndex::Const(-(calc_refcount_offset(elem_layout) as i32))], + &[GepIndex::Const( + -(calc_data_prefix_offset(elem_layout) as i32), + )], IntegerType::new(context, 8).into(), )?; + block.append_operation(ReallocBindingsMeta::free(context, data_ptr, location)?); block.append_operation(ReallocBindingsMeta::free( context, - array_allocation_ptr, + array_ptr_ptr, location, )?); @@ -436,8 +482,7 @@ pub fn build_tuple_from_span<'ctx, 'this>( } { - // if the length doesn't match, free the tuple. - + // When there's a length mismatch, just consume (drop) the array. metadata .get::() .ok_or(Error::MissingMetadata)? @@ -465,15 +510,6 @@ pub fn build_append<'ctx, 'this>( metadata: &mut MetadataStorage, info: &SignatureAndTypeConcreteLibfunc, ) -> Result<()> { - /* - * 1. Check if shared. - * 2. If shared: - * 1. Deep clone with space for at least 1 extra element. - * 3. If not shared: - * 1. Either realloc, move or do nothing. - * 4. Append element. - */ - metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, helper)); let self_ty = registry.build_type( @@ -486,48 +522,22 @@ pub fn build_append<'ctx, 'this>( let ptr_ty = llvm::r#type::pointer(context, 0); let len_ty = IntegerType::new(context, 32).into(); - let (elem_ty, elem_layout) = - registry.build_type_with_layout(context, helper, metadata, &info.ty)?; + let (_, elem_layout) = registry.build_type_with_layout(context, helper, metadata, &info.ty)?; let elem_stride = entry.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; - let k0 = entry.const_int(context, location, 0, 32)?; - let k1 = entry.const_int(context, location, 1, 32)?; - - let array_ptr = entry.extract_value(context, location, entry.argument(0)?.into(), ptr_ty, 0)?; - let array_start = - entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 1)?; - let array_end = entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 2)?; - let array_capacity = - entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 3)?; - - let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; - let array_size = entry.append_op_result(arith::extui( - array_len, - IntegerType::new(context, 64).into(), - location, - ))?; - let array_size = entry.append_op_result(arith::muli(array_size, elem_stride, location))?; - - let data_offset = entry.append_op_result(arith::extui( - array_start, - IntegerType::new(context, 64).into(), - location, - ))?; - let data_offset = entry.append_op_result(arith::muli(data_offset, elem_stride, location))?; - let data_ptr = entry.gep( - context, - location, - array_ptr, - &[GepIndex::Value(data_offset)], - IntegerType::new(context, 8).into(), - )?; + // If is_empty + // - Allocate initial space. + // Else if it has no space + // - Reallocate + // + // Push item. fn compute_next_capacity<'ctx, 'this>( context: &'ctx Context, block: &'this Block<'ctx>, location: Location<'ctx>, elem_stride: Value<'ctx, 'this>, - array_end: Value<'ctx, 'this>, + array_capacity: Value<'ctx, 'this>, ) -> Result<(Value<'ctx, 'this>, Value<'ctx, 'this>)> { let len_ty = IntegerType::new(context, 32).into(); @@ -535,9 +545,10 @@ pub fn build_append<'ctx, 'this>( let k8 = block.const_int_from_type(context, location, 8, len_ty)?; let k1024 = block.const_int_from_type(context, location, 1024, len_ty)?; - let realloc_len = block.append_op_result(arith::shli(array_end, k1, location))?; + let realloc_len = block.append_op_result(arith::shli(array_capacity, k1, location))?; let realloc_len = block.append_op_result(arith::minui(realloc_len, k1024, location))?; - let realloc_len = block.append_op_result(arith::addi(realloc_len, array_end, location))?; + let realloc_len = + block.append_op_result(arith::addi(realloc_len, array_capacity, location))?; let realloc_len = block.append_op_result(arith::maxui(realloc_len, k8, location))?; let realloc_size = block.append_op_result(arith::extui( @@ -551,192 +562,60 @@ pub fn build_append<'ctx, 'this>( Result::Ok((realloc_len, realloc_size)) } - let is_empty = entry.append_op_result(arith::cmpi( - context, - CmpiPredicate::Eq, - array_capacity, - k0, - location, - ))?; + let data_prefix_size = calc_data_prefix_offset(elem_layout); - let is_shared = entry.append_op_result(scf::r#if( + let array_capacity = + entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 3)?; + let k0 = entry.const_int_from_type(context, location, 0, len_ty)?; + let is_empty = entry.cmpi(context, CmpiPredicate::Eq, array_capacity, k0, location)?; + let array_obj = entry.append_op_result(scf::r#if( is_empty, - &[IntegerType::new(context, 1).into()], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let k0 = block.const_int(context, location, 0, 1)?; - - block.append_operation(scf::r#yield(&[k0], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let is_shared = is_shared(context, entry, location, array_ptr, elem_layout)?; - - block.append_operation(scf::r#yield(&[is_shared], location)); - region - }, - location, - ))?; - - let value = entry.append_op_result(scf::r#if( - is_shared, &[self_ty], { let region = Region::new(); let block = region.append_block(Block::new(&[])); - let has_space = block.append_op_result(arith::cmpi( - context, - CmpiPredicate::Ugt, - array_capacity, - array_len, - location, - ))?; - - let op = block.append_operation(scf::r#if( - has_space, - &[len_ty, IntegerType::new(context, 64).into()], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let clone_size = block.append_op_result(arith::extui( - array_capacity, - IntegerType::new(context, 64).into(), - location, - ))?; - let clone_size = - block.append_op_result(arith::muli(clone_size, elem_stride, location))?; - - block.append_operation(scf::r#yield(&[array_capacity, clone_size], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let (realloc_capacity, realloc_size) = - compute_next_capacity(context, &block, location, elem_stride, array_end)?; - - block.append_operation(scf::r#yield( - &[realloc_capacity, realloc_size], - location, - )); - region - }, - location, - )); - let clone_capacity = op.result(0)?.into(); - let clone_size = op.result(1)?.into(); + let (array_capacity, realloc_len) = + compute_next_capacity(context, &block, location, elem_stride, array_capacity)?; - let clone_size_with_refcount = block.append_op_result(arith::addi( - clone_size, - block.const_int(context, location, calc_refcount_offset(elem_layout), 64)?, - location, - ))?; + let data_prefix_size = block.const_int(context, location, data_prefix_size, 64)?; + let realloc_len = block.addi(realloc_len, data_prefix_size, location)?; - let clone_ptr = block.append_op_result(llvm::zero(ptr_ty, location))?; - let clone_ptr = block.append_op_result(ReallocBindingsMeta::realloc( + let null_ptr = block.append_op_result(llvm::zero(ptr_ty, location))?; + let array_ptr = block.append_op_result(ReallocBindingsMeta::realloc( context, - clone_ptr, - clone_size_with_refcount, + null_ptr, + realloc_len, location, )?)?; - block.store(context, location, clone_ptr, k1)?; - - let clone_ptr = block.gep( - context, - location, - clone_ptr, - &[GepIndex::Const(calc_refcount_offset(elem_layout) as i32)], - IntegerType::new(context, 8).into(), - )?; - - match metadata.get::() { - Some(dup_overrides_meta) if dup_overrides_meta.is_overriden(&info.ty) => { - let k0 = block.const_int(context, location, 0, 64)?; - block.append_operation(scf::r#for( - k0, - array_size, - elem_stride, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[( - IntegerType::new(context, 64).into(), - location, - )])); - - let offset = block.argument(0)?.into(); - let source_ptr = block.gep( - context, - location, - data_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - let target_ptr = block.gep( - context, - location, - clone_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - - let value = block.load(context, location, source_ptr, elem_ty)?; - let values = dup_overrides_meta - .invoke_override(context, &block, location, &info.ty, value)?; - block.store(context, location, source_ptr, values.0)?; - block.store(context, location, target_ptr, values.1)?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); - } - _ => block.memcpy(context, location, array_ptr, clone_ptr, clone_size), - } - - let clone_value = block.append_op_result(llvm::zero(self_ty, location))?; - let clone_value = block.insert_values( - context, - location, - clone_value, - &[clone_ptr, k0, array_len, clone_capacity], - )?; - metadata - .get::() - .unwrap() - .invoke_override( - context, - &block, - location, - &info.signature.param_signatures[0].ty, - entry.argument(0)?.into(), - )?; + let k8 = block.const_int(context, location, 8, 64)?; + let array_ptr_ptr = block.append_op_result(ReallocBindingsMeta::realloc( + context, null_ptr, k8, location, + )?)?; + block.store(context, location, array_ptr_ptr, array_ptr)?; - block.append_operation(scf::r#yield(&[clone_value], location)); + let array_obj = entry.argument(0)?.into(); + let array_obj = block.insert_value(context, location, array_obj, array_ptr_ptr, 0)?; + let array_obj = block.insert_value(context, location, array_obj, array_capacity, 3)?; + block.append_operation(scf::r#yield(&[array_obj], location)); region }, { let region = Region::new(); let block = region.append_block(Block::new(&[])); - let has_tail_space = block.append_op_result(arith::cmpi( + let array_end = + block.extract_value(context, location, entry.argument(0)?.into(), len_ty, 2)?; + let has_space = block.cmpi( context, CmpiPredicate::Ult, array_end, array_capacity, location, - ))?; - let array_value = block.append_op_result(scf::r#if( - has_tail_space, + )?; + let array_obj = block.append_op_result(scf::r#if( + has_space, &[self_ty], { let region = Region::new(); @@ -749,1284 +628,993 @@ pub fn build_append<'ctx, 'this>( let region = Region::new(); let block = region.append_block(Block::new(&[])); - let has_head_space = block.append_op_result(arith::cmpi( + let (array_capacity, realloc_len) = compute_next_capacity( + context, + &block, + location, + elem_stride, + array_capacity, + )?; + + let data_prefix_size = + block.const_int(context, location, data_prefix_size, 64)?; + let realloc_len = block.addi(realloc_len, data_prefix_size, location)?; + + let array_ptr_ptr = block.extract_value( context, - CmpiPredicate::Ugt, - array_start, - k0, location, - ))?; - let array_value = block.append_op_result(scf::r#if( - has_head_space, - &[self_ty], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - block.append_operation( - ods::llvm::intr_memmove( - context, - array_ptr, - data_ptr, - array_size, - IntegerAttribute::new(IntegerType::new(context, 1).into(), 0), - location, - ) - .into(), - ); - - let array_value = block.insert_value( - context, - location, - entry.argument(0)?.into(), - k0, - 1, - )?; - let array_value = - block.insert_value(context, location, array_value, array_len, 2)?; - - block.append_operation(scf::r#yield(&[array_value], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let offset_array_ptr = block.gep( - context, - location, - array_ptr, - &[GepIndex::Const(-(calc_refcount_offset(elem_layout) as i32))], - IntegerType::new(context, 8).into(), - )?; - let array_ptr = block.append_op_result(arith::select( - is_empty, - array_ptr, - offset_array_ptr, - location, - ))?; - - let (realloc_len, realloc_size) = compute_next_capacity( - context, - &block, - location, - elem_stride, - array_end, - )?; - let realloc_size_with_refcount = - block.append_op_result(arith::addi( - realloc_size, - block.const_int( - context, - location, - calc_refcount_offset(elem_layout), - 64, - )?, - location, - ))?; - - let array_ptr = - block.append_op_result(ReallocBindingsMeta::realloc( - context, - array_ptr, - realloc_size_with_refcount, - location, - )?)?; - - let ref_count = block.load(context, location, array_ptr, len_ty)?; - let ref_count = block.append_op_result(arith::select( - is_empty, k1, ref_count, location, - ))?; - block.store(context, location, array_ptr, ref_count)?; - - let array_ptr = block.gep( - context, - location, - array_ptr, - &[GepIndex::Const(calc_refcount_offset(elem_layout) as i32)], - IntegerType::new(context, 8).into(), - )?; - - let array_value = block.insert_value( - context, - location, - entry.argument(0)?.into(), - array_ptr, - 0, - )?; - let array_value = block.insert_value( - context, - location, - array_value, - realloc_len, - 3, - )?; - - block.append_operation(scf::r#yield(&[array_value], location)); - region - }, + entry.argument(0)?.into(), + ptr_ty, + 0, + )?; + let array_ptr = block.load(context, location, array_ptr_ptr, ptr_ty)?; + let array_ptr = block.append_op_result(ReallocBindingsMeta::realloc( + context, + array_ptr, + realloc_len, location, - ))?; + )?)?; + block.store(context, location, array_ptr_ptr, array_ptr)?; - block.append_operation(scf::r#yield(&[array_value], location)); + let array_obj = block.insert_value( + context, + location, + entry.argument(0)?.into(), + array_capacity, + 3, + )?; + block.append_operation(scf::r#yield(&[array_obj], location)); region }, location, ))?; - block.append_operation(scf::r#yield(&[array_value], location)); + block.append_operation(scf::r#yield(&[array_obj], location)); region }, location, ))?; - let array_ptr = entry.extract_value(context, location, value, ptr_ty, 0)?; - let array_end = entry.extract_value(context, location, value, len_ty, 2)?; + let array_ptr_ptr = entry.extract_value(context, location, array_obj, ptr_ty, 0)?; + let array_ptr = entry.load(context, location, array_ptr_ptr, ptr_ty)?; - let data_offset = entry.append_op_result(arith::extui( - array_end, + let target_offset = entry.extract_value(context, location, array_obj, len_ty, 2)?; + let target_offset = entry.extui( + target_offset, IntegerType::new(context, 64).into(), location, - ))?; - let data_offset = entry.append_op_result(arith::muli(data_offset, elem_stride, location))?; - let data_ptr = entry.gep( + )?; + let target_offset = entry.muli(target_offset, elem_stride, location)?; + let target_ptr = entry.gep( context, location, array_ptr, - &[GepIndex::Value(data_offset)], + &[GepIndex::Value(target_offset)], IntegerType::new(context, 8).into(), )?; - entry.store(context, location, data_ptr, entry.argument(1)?.into())?; - let array_end = entry.append_op_result(arith::addi(array_end, k1, location))?; - let value = entry.insert_value(context, location, value, array_end, 2)?; + entry.store(context, location, target_ptr, entry.argument(1)?.into())?; - entry.append_operation(helper.br(0, &[value], location)); + entry.append_operation(helper.br(0, &[array_obj], location)); Ok(()) } -#[derive(Clone, Copy)] -enum PopInfo<'a> { - Single(&'a SignatureAndTypeConcreteLibfunc), - Multi(&'a ConcreteMultiPopLibfunc), -} +// /// Generate MLIR operations for the `array_pop_*` libfuncs. +// /// +// /// Template arguments: +// /// - Consume: Whether to consume or not the array on failure. +// /// - Reverse: False for front-popping, true for back-popping. +// /// +// /// The `info` argument contains how many items to pop. +// fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( +// context: &'ctx Context, +// registry: &ProgramRegistry, +// entry: &'this Block<'ctx>, +// location: Location<'ctx>, +// helper: &LibfuncHelper<'ctx, 'this>, +// metadata: &mut MetadataStorage, +// info: PopInfo, +// ) -> Result<()> { +// /* +// * 1. Check if there's enough data to pop. +// * 2. If there is not enough data, maybe consume and return. +// * 3. Allocate output. +// * 4. Clone or copy the popped data. +// * - Clone if shared. +// * - Copy if not shared. +// */ +// metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, helper)); + +// let ptr_ty = llvm::r#type::pointer(context, 0); +// let len_ty = IntegerType::new(context, 32).into(); + +// let (self_ty, elem_ty, array_value, extract_len, mut branch_values) = match info { +// PopInfo::Single(info) => ( +// &info.signature.param_signatures[0].ty, +// &info.ty, +// entry.argument(0)?.into(), +// 1, +// Vec::new(), +// ), +// PopInfo::Multi(ConcreteMultiPopLibfunc { +// popped_ty, +// signature, +// }) => { +// let range_check = super::increment_builtin_counter( +// context, +// entry, +// location, +// entry.argument(0)?.into(), +// )?; + +// let CoreTypeConcrete::Snapshot(InfoAndTypeConcreteType { ty, .. }) = +// registry.get_type(&signature.param_signatures[1].ty)? +// else { +// return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); +// }; + +// let CoreTypeConcrete::Array(InfoAndTypeConcreteType { ty, .. }) = +// registry.get_type(ty)? +// else { +// return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); +// }; + +// let CoreTypeConcrete::Struct(info) = registry.get_type(popped_ty)? else { +// return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); +// }; +// debug_assert!(info.members.iter().all(|member_ty| member_ty == ty)); + +// ( +// &signature.param_signatures[1].ty, +// ty, +// entry.argument(1)?.into(), +// info.members.len(), +// vec![range_check], +// ) +// } +// }; + +// registry.build_type(context, helper, metadata, self_ty)?; +// let extract_len_value = entry.const_int_from_type(context, location, extract_len, len_ty)?; + +// let (elem_type, elem_layout) = +// registry.build_type_with_layout(context, helper, metadata, elem_ty)?; + +// let array_start = entry.extract_value(context, location, array_value, len_ty, 1)?; +// let array_end = entry.extract_value(context, location, array_value, len_ty, 2)?; + +// let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; +// let has_enough_data = entry.append_op_result(arith::cmpi( +// context, +// CmpiPredicate::Ule, +// extract_len_value, +// array_len, +// location, +// ))?; + +// let valid_block = helper.append_block(Block::new(&[])); +// let error_block = helper.append_block(Block::new(&[])); +// entry.append_operation(cf::cond_br( +// context, +// has_enough_data, +// valid_block, +// error_block, +// &[], +// &[], +// location, +// )); + +// { +// // Clone branch_values so that it doesn't interfere with the other branch. +// let mut branch_values = branch_values.clone(); + +// let value_size = valid_block.const_int( +// context, +// location, +// elem_layout.pad_to_align().size() * extract_len, +// 64, +// )?; + +// let value_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; +// let value_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( +// context, value_ptr, value_size, location, +// )?)?; + +// let array_ptr_ptr = valid_block.extract_value(context, location, array_value, ptr_ty, 0)?; +// let is_shared = is_shared(context, valid_block, location, array_ptr_ptr, elem_layout)?; + +// let array_ptr = valid_block.load(context, location, array_ptr_ptr, ptr_ty)?; +// let data_ptr = { +// let offset_elems = if REVERSE { +// valid_block.append_op_result(arith::subi(array_end, extract_len_value, location))? +// } else { +// array_start +// }; + +// let offset = valid_block.append_op_result(arith::extui( +// offset_elems, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let elem_stride = +// valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; +// let offset = +// valid_block.append_op_result(arith::muli(offset, elem_stride, location))?; + +// valid_block.gep( +// context, +// location, +// array_ptr, +// &[GepIndex::Value(offset)], +// IntegerType::new(context, 8).into(), +// )? +// }; + +// let array_value = +// valid_block.insert_value(context, location, array_value, new_array_ptr, 0)?; + +// let has_realloc = valid_block.append_op_result( +// ods::llvm::icmp( +// context, +// IntegerType::new(context, 1).into(), +// array_ptr, +// new_array_ptr, +// IntegerAttribute::new(IntegerType::new(context, 64).into(), 1).into(), +// location, +// ) +// .into(), +// )?; +// let array_value = valid_block.append_op_result(scf::r#if( +// has_realloc, +// &[array_value.r#type()], +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[])); + +// let k0 = block.const_int_from_type(context, location, 0, len_ty)?; +// let array_len = +// block.append_op_result(arith::subi(array_len, extract_len_value, location))?; + +// let array_value = block.insert_value(context, location, array_value, k0, 1)?; +// let array_value = +// block.insert_value(context, location, array_value, array_len, 2)?; +// let array_value = +// block.insert_value(context, location, array_value, array_len, 3)?; + +// block.append_operation(scf::r#yield(&[array_value], location)); +// region +// }, +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[])); + +// let array_value = if REVERSE { +// let array_end = block.append_op_result(arith::subi( +// array_end, +// extract_len_value, +// location, +// ))?; +// block.insert_value(context, location, array_value, array_end, 2)? +// } else { +// let array_start = block.append_op_result(arith::addi( +// array_start, +// extract_len_value, +// location, +// ))?; +// block.insert_value(context, location, array_value, array_start, 1)? +// }; + +// block.append_operation(scf::r#yield(&[array_value], location)); +// region +// }, +// location, +// ))?; + +// branch_values.push(array_value); +// branch_values.push(value_ptr); + +// valid_block.append_operation(helper.br(0, &branch_values, location)); +// } + +// { +// if CONSUME { +// let self_ty = match info { +// PopInfo::Single(info) => &info.signature.param_signatures[0].ty, +// PopInfo::Multi(info) => &info.signature.param_signatures[1].ty, +// }; + +// metadata +// .get::() +// .unwrap() +// .invoke_override(context, error_block, location, self_ty, array_value)?; +// } else { +// branch_values.push(array_value); +// } + +// error_block.append_operation(helper.br(1, &branch_values, location)); +// } + +// Ok(()) +// } + +// /// Generate MLIR operations for the `array_get` libfunc. +// pub fn build_get<'ctx, 'this>( +// context: &'ctx Context, +// registry: &ProgramRegistry, +// entry: &'this Block<'ctx>, +// location: Location<'ctx>, +// helper: &LibfuncHelper<'ctx, 'this>, +// metadata: &mut MetadataStorage, +// info: &SignatureAndTypeConcreteLibfunc, +// ) -> Result<()> { +// let ptr_ty = llvm::r#type::pointer(context, 0); +// let len_ty = IntegerType::new(context, 32).into(); + +// // Build the type so that the drop impl invocation works properly. +// registry.build_type( +// context, +// helper, +// metadata, +// &info.signature.param_signatures[1].ty, +// )?; + +// let range_check = +// super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; + +// let array_start = +// entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 1)?; +// let array_end = entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 2)?; + +// let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; +// let is_valid = entry.append_op_result(arith::cmpi( +// context, +// CmpiPredicate::Ult, +// entry.argument(2)?.into(), +// array_len, +// location, +// ))?; + +// let valid_block = helper.append_block(Block::new(&[])); +// let error_block = helper.append_block(Block::new(&[])); +// entry.append_operation(cf::cond_br( +// context, +// is_valid, +// valid_block, +// error_block, +// &[], +// &[], +// location, +// )); + +// { +// let (elem_ty, elem_layout) = +// registry.build_type_with_layout(context, helper, metadata, &info.ty)?; +// let elem_stride = +// valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; + +// let value_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; +// let value_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( +// context, +// value_ptr, +// elem_stride, +// location, +// )?)?; + +// let array_ptr = +// valid_block.extract_value(context, location, entry.argument(1)?.into(), ptr_ty, 0)?; +// let is_shared = is_shared(context, valid_block, location, array_ptr, elem_layout)?; + +// let offset = valid_block.append_op_result(arith::addi( +// array_start, +// entry.argument(2)?.into(), +// location, +// ))?; +// let offset = valid_block.append_op_result(arith::extui( +// offset, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let offset = valid_block.append_op_result(arith::muli(offset, elem_stride, location))?; + +// let source_ptr = valid_block.gep( +// context, +// location, +// array_ptr, +// &[GepIndex::Value(offset)], +// IntegerType::new(context, 8).into(), +// )?; + +// valid_block.append_operation(scf::r#if( +// is_shared, +// &[], +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[])); + +// match metadata.get::() { +// Some(dup_overrides_meta) if dup_overrides_meta.is_overriden(&info.ty) => { +// let value = block.load(context, location, source_ptr, elem_ty)?; +// let values = dup_overrides_meta +// .invoke_override(context, &block, location, &info.ty, value)?; +// block.store(context, location, source_ptr, values.0)?; +// block.store(context, location, value_ptr, values.1)?; +// } +// _ => block.memcpy(context, location, source_ptr, value_ptr, elem_stride), +// } + +// metadata +// .get::() +// .unwrap() +// .invoke_override( +// context, +// &block, +// location, +// &info.signature.param_signatures[1].ty, +// entry.argument(1)?.into(), +// )?; + +// block.append_operation(scf::r#yield(&[], location)); +// region +// }, +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[])); + +// block.memcpy(context, location, source_ptr, value_ptr, elem_stride); + +// match metadata.get::() { +// Some(drop_overrides_meta) if drop_overrides_meta.is_overriden(&info.ty) => { +// let drop_loop = |o0, o1| { +// block.append_operation(scf::r#for( +// o0, +// o1, +// elem_stride, +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[( +// IntegerType::new(context, 64).into(), +// location, +// )])); + +// let value_ptr = block.gep( +// context, +// location, +// array_ptr, +// &[GepIndex::Value(block.argument(0)?.into())], +// IntegerType::new(context, 8).into(), +// )?; +// let value = +// block.load(context, location, value_ptr, elem_ty)?; +// drop_overrides_meta.invoke_override( +// context, &block, location, &info.ty, value, +// )?; + +// block.append_operation(scf::r#yield(&[], location)); +// region +// }, +// location, +// )); + +// Result::Ok(()) +// }; + +// let o0 = block.append_op_result(arith::extui( +// array_start, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let o1 = block.append_op_result(arith::addi( +// array_start, +// entry.argument(2)?.into(), +// location, +// ))?; +// let o1 = block.append_op_result(arith::extui( +// o1, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let o0 = block.append_op_result(arith::muli(o0, elem_stride, location))?; +// let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; +// drop_loop(o0, o1)?; + +// let o0 = block.append_op_result(arith::addi(o1, elem_stride, location))?; +// let o1 = block.append_op_result(arith::extui( +// array_end, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; +// drop_loop(o0, o1)?; +// } +// _ => {} +// } + +// let array_ptr = block.gep( +// context, +// location, +// array_ptr, +// &[GepIndex::Const( +// -(calc_data_prefix_offset(elem_layout) as i32), +// )], +// IntegerType::new(context, 8).into(), +// )?; +// block.append_operation(ReallocBindingsMeta::free(context, array_ptr, location)?); + +// block.append_operation(scf::r#yield(&[], location)); +// region +// }, +// location, +// )); + +// valid_block.append_operation(helper.br(0, &[range_check, value_ptr], location)); +// } + +// { +// metadata +// .get::() +// .unwrap() +// .invoke_override( +// context, +// error_block, +// location, +// &info.signature.param_signatures[1].ty, +// entry.argument(1)?.into(), +// )?; + +// error_block.append_operation(helper.br(1, &[range_check], location)); +// } + +// Ok(()) +// } + +// /// Generate MLIR operations for the `array_slice` libfunc. +// pub fn build_slice<'ctx, 'this>( +// context: &'ctx Context, +// registry: &ProgramRegistry, +// entry: &'this Block<'ctx>, +// location: Location<'ctx>, +// helper: &LibfuncHelper<'ctx, 'this>, +// metadata: &mut MetadataStorage, +// info: &SignatureAndTypeConcreteLibfunc, +// ) -> Result<()> { +// // Signature: +// // Params: RangeCheck, Snapshot>, u32, u32 +// // Branches: +// // 0: RangeCheck, Snapshot> +// // 1: RangeCheck + +// let ptr_ty = llvm::r#type::pointer(context, 0); +// let len_ty = IntegerType::new(context, 32).into(); + +// let self_ty = registry.build_type( +// context, +// helper, +// metadata, +// &info.signature.param_signatures[1].ty, +// )?; + +// let range_check = +// super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; + +// let k0 = entry.const_int_from_type(context, location, 0, len_ty)?; +// let k1 = entry.const_int_from_type(context, location, 1, len_ty)?; + +// let array_start = +// entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 1)?; +// let array_end = entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 2)?; +// let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; + +// let slice_start = entry.argument(2)?.into(); +// let slice_len = entry.argument(3)?.into(); +// let slice_end = entry.append_op_result(arith::addi(slice_start, slice_len, location))?; + +// let slice_lhs_bound = entry.append_op_result(arith::cmpi( +// context, +// CmpiPredicate::Ule, +// slice_start, +// array_len, +// location, +// ))?; +// let slice_rhs_bound = entry.append_op_result(arith::cmpi( +// context, +// CmpiPredicate::Ule, +// slice_end, +// array_len, +// location, +// ))?; +// let slice_bounds = +// entry.append_op_result(arith::andi(slice_lhs_bound, slice_rhs_bound, location))?; + +// let valid_block = helper.append_block(Block::new(&[])); +// let error_block = helper.append_block(Block::new(&[])); +// entry.append_operation(cf::cond_br( +// context, +// slice_bounds, +// valid_block, +// error_block, +// &[], +// &[], +// location, +// )); + +// { +// let (elem_ty, elem_layout) = +// registry.build_type_with_layout(context, helper, metadata, &info.ty)?; +// let elem_stride = +// valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; + +// let slice_size = valid_block.append_op_result(arith::extui( +// slice_len, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let slice_size = +// valid_block.append_op_result(arith::muli(elem_stride, slice_size, location))?; +// let slice_size_with_offset = valid_block.append_op_result(arith::addi( +// slice_size, +// valid_block.const_int(context, location, calc_data_prefix_offset(elem_layout), 64)?, +// location, +// ))?; + +// let array_ptr = +// valid_block.extract_value(context, location, entry.argument(1)?.into(), ptr_ty, 0)?; +// let null_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; +// let is_null_source = valid_block.append_op_result( +// ods::llvm::icmp( +// context, +// IntegerType::new(context, 1).into(), +// array_ptr, +// null_ptr, +// IntegerAttribute::new(IntegerType::new(context, 64).into(), 0).into(), +// location, +// ) +// .into(), +// )?; +// let slice_ptr = valid_block.append_op_result(scf::r#if( +// is_null_source, +// &[ptr_ty], +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[])); + +// block.append_operation(scf::r#yield(&[null_ptr], location)); +// region +// }, +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[])); + +// let slice_ptr = block.append_op_result(llvm::zero(ptr_ty, location))?; +// let slice_ptr = block.append_op_result(ReallocBindingsMeta::realloc( +// context, +// slice_ptr, +// slice_size_with_offset, +// location, +// )?)?; +// block.store(context, location, slice_ptr, k1)?; + +// let slice_ptr = block.gep( +// context, +// location, +// slice_ptr, +// &[GepIndex::Const(calc_data_prefix_offset(elem_layout) as i32)], +// IntegerType::new(context, 8).into(), +// )?; + +// let is_shared = is_shared(context, &block, location, array_ptr, elem_layout)?; + +// let offset = +// block.append_op_result(arith::addi(array_start, slice_start, location))?; +// let offset = block.append_op_result(arith::extui( +// offset, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let offset = block.append_op_result(arith::muli(offset, elem_stride, location))?; + +// let source_ptr = block.gep( +// context, +// location, +// array_ptr, +// &[GepIndex::Value(offset)], +// IntegerType::new(context, 8).into(), +// )?; + +// block.append_operation(scf::r#if( +// is_shared, +// &[], +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[])); + +// match metadata.get::() { +// Some(dup_overrides_meta) +// if dup_overrides_meta.is_overriden(&info.ty) => +// { +// let k0 = block.const_int(context, location, 0, 64)?; +// block.append_operation(scf::r#for( +// k0, +// slice_size, +// elem_stride, +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[( +// IntegerType::new(context, 64).into(), +// location, +// )])); + +// let offset = block.argument(0)?.into(); +// let source_ptr = block.gep( +// context, +// location, +// source_ptr, +// &[GepIndex::Value(offset)], +// IntegerType::new(context, 8).into(), +// )?; +// let target_ptr = block.gep( +// context, +// location, +// slice_ptr, +// &[GepIndex::Value(offset)], +// IntegerType::new(context, 8).into(), +// )?; + +// let value = +// block.load(context, location, source_ptr, elem_ty)?; +// let values = dup_overrides_meta.invoke_override( +// context, &block, location, &info.ty, value, +// )?; +// block.store(context, location, source_ptr, values.0)?; +// block.store(context, location, target_ptr, values.1)?; + +// block.append_operation(scf::r#yield(&[], location)); +// region +// }, +// location, +// )); +// } +// _ => block.memcpy(context, location, source_ptr, slice_ptr, slice_size), +// } + +// metadata +// .get::() +// .unwrap() +// .invoke_override( +// context, +// &block, +// location, +// &info.signature.param_signatures[1].ty, +// entry.argument(1)?.into(), +// )?; + +// block.append_operation(scf::r#yield(&[], location)); +// region +// }, +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[])); + +// block.memcpy(context, location, source_ptr, slice_ptr, slice_size); + +// match metadata.get::() { +// Some(drop_overrides_meta) +// if drop_overrides_meta.is_overriden(&info.ty) => +// { +// let drop_loop = |o0, o1| { +// block.append_operation(scf::r#for( +// o0, +// o1, +// elem_stride, +// { +// let region = Region::new(); +// let block = region.append_block(Block::new(&[( +// IntegerType::new(context, 64).into(), +// location, +// )])); + +// let value_ptr = block.gep( +// context, +// location, +// array_ptr, +// &[GepIndex::Value(block.argument(0)?.into())], +// IntegerType::new(context, 8).into(), +// )?; +// let value = block +// .load(context, location, value_ptr, elem_ty)?; +// drop_overrides_meta.invoke_override( +// context, &block, location, &info.ty, value, +// )?; + +// block.append_operation(scf::r#yield(&[], location)); +// region +// }, +// location, +// )); + +// Result::Ok(()) +// }; + +// let o0 = block.append_op_result(arith::extui( +// array_start, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let o1 = block.append_op_result(arith::addi( +// array_start, +// slice_start, +// location, +// ))?; +// let o1 = block.append_op_result(arith::extui( +// o1, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let o0 = block.append_op_result(arith::muli( +// o0, +// elem_stride, +// location, +// ))?; +// let o1 = block.append_op_result(arith::muli( +// o1, +// elem_stride, +// location, +// ))?; +// drop_loop(o0, o1)?; + +// let o0 = block +// .append_op_result(arith::addi(o1, slice_size, location))?; +// let o1 = block.append_op_result(arith::extui( +// array_end, +// IntegerType::new(context, 64).into(), +// location, +// ))?; +// let o1 = block.append_op_result(arith::muli( +// o1, +// elem_stride, +// location, +// ))?; +// drop_loop(o0, o1)?; +// } +// _ => {} +// } + +// let array_ptr = block.gep( +// context, +// location, +// array_ptr, +// &[GepIndex::Const( +// -(calc_data_prefix_offset(elem_layout) as i32), +// )], +// IntegerType::new(context, 8).into(), +// )?; +// block.append_operation(ReallocBindingsMeta::free( +// context, array_ptr, location, +// )?); + +// block.append_operation(scf::r#yield(&[], location)); +// region +// }, +// location, +// )); + +// block.append_operation(scf::r#yield(&[slice_ptr], location)); +// region +// }, +// location, +// ))?; + +// let slice_value = valid_block.append_op_result(llvm::undef(self_ty, location))?; +// let slice_value = valid_block.insert_values( +// context, +// location, +// slice_value, +// &[slice_ptr, k0, slice_len, slice_len], +// )?; + +// valid_block.append_operation(helper.br(0, &[range_check, slice_value], location)); +// } + +// { +// metadata +// .get::() +// .ok_or(Error::MissingMetadata)? +// .invoke_override( +// context, +// error_block, +// location, +// &info.signature.param_signatures[1].ty, +// entry.argument(1)?.into(), +// )?; + +// error_block.append_operation(helper.br(1, &[range_check], location)); +// } + +// Ok(()) +// } + +// /// Generate MLIR operations for the `array_len` libfunc. +// pub fn build_len<'ctx, 'this>( +// context: &'ctx Context, +// _registry: &ProgramRegistry, +// entry: &'this Block<'ctx>, +// location: Location<'ctx>, +// helper: &LibfuncHelper<'ctx, 'this>, +// metadata: &mut MetadataStorage, +// info: &SignatureAndTypeConcreteLibfunc, +// ) -> Result<()> { +// let len_ty = IntegerType::new(context, 32).into(); + +// let array_start = +// entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 1)?; +// let array_end = entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 2)?; + +// let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; + +// metadata +// .get::() +// .unwrap() +// .invoke_override( +// context, +// entry, +// location, +// &info.signature.param_signatures[0].ty, +// entry.argument(0)?.into(), +// )?; + +// entry.append_operation(helper.br(0, &[array_len], location)); +// Ok(()) +// } -/// Generate MLIR operations for the `array_pop_*` libfuncs. -/// -/// Template arguments: -/// - Consume: Whether to consume or not the array on failure. -/// - Reverse: False for front-popping, true for back-popping. -/// -/// The `info` argument contains how many items to pop. -fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( +fn is_shared<'ctx, 'this>( context: &'ctx Context, - registry: &ProgramRegistry, - entry: &'this Block<'ctx>, + block: &'this Block<'ctx>, location: Location<'ctx>, - helper: &LibfuncHelper<'ctx, 'this>, - metadata: &mut MetadataStorage, - info: PopInfo, -) -> Result<()> { - /* - * 1. Check if there's enough data to pop. - * 2. If there is not enough data, maybe consume and return. - * 3. Allocate output. - * 4. Clone or copy the popped data. - * - Clone if shared. - * - Copy if not shared. - */ - - metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, helper)); - - let ptr_ty = llvm::r#type::pointer(context, 0); - let len_ty = IntegerType::new(context, 32).into(); - - let (self_ty, elem_ty, array_value, extract_len, mut branch_values) = match info { - PopInfo::Single(info) => ( - &info.signature.param_signatures[0].ty, - &info.ty, - entry.argument(0)?.into(), - 1, - Vec::new(), - ), - PopInfo::Multi(ConcreteMultiPopLibfunc { - popped_ty, - signature, - }) => { - let range_check = super::increment_builtin_counter( - context, - entry, - location, - entry.argument(0)?.into(), - )?; - - let CoreTypeConcrete::Snapshot(InfoAndTypeConcreteType { ty, .. }) = - registry.get_type(&signature.param_signatures[1].ty)? - else { - return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); - }; - - let CoreTypeConcrete::Array(InfoAndTypeConcreteType { ty, .. }) = - registry.get_type(ty)? - else { - return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); - }; - - let CoreTypeConcrete::Struct(info) = registry.get_type(popped_ty)? else { - return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); - }; - debug_assert!(info.members.iter().all(|member_ty| member_ty == ty)); - - ( - &signature.param_signatures[1].ty, - ty, - entry.argument(1)?.into(), - info.members.len(), - vec![range_check], - ) - } - }; - - registry.build_type(context, helper, metadata, self_ty)?; - let extract_len_value = entry.const_int_from_type(context, location, extract_len, len_ty)?; - - let (elem_type, elem_layout) = - registry.build_type_with_layout(context, helper, metadata, elem_ty)?; - - let array_start = entry.extract_value(context, location, array_value, len_ty, 1)?; - let array_end = entry.extract_value(context, location, array_value, len_ty, 2)?; - - let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; - let has_enough_data = entry.append_op_result(arith::cmpi( - context, - CmpiPredicate::Ule, - extract_len_value, - array_len, - location, - ))?; - - let valid_block = helper.append_block(Block::new(&[])); - let error_block = helper.append_block(Block::new(&[])); - entry.append_operation(cf::cond_br( - context, - has_enough_data, - valid_block, - error_block, - &[], - &[], - location, - )); - - { - // Clone branch_values so that it doesn't interfere with the other branch. - let mut branch_values = branch_values.clone(); - - let value_size = valid_block.const_int( + array_ptr_ptr: Value<'ctx, 'this>, + elem_layout: Layout, +) -> Result> { + let null_ptr = + block.append_op_result(llvm::zero(llvm::r#type::pointer(context, 0), location))?; + let ptr_is_null = block.append_op_result( + ods::llvm::icmp( context, + IntegerType::new(context, 1).into(), + array_ptr_ptr, + null_ptr, + IntegerAttribute::new(IntegerType::new(context, 64).into(), 0).into(), location, - elem_layout.pad_to_align().size() * extract_len, - 64, - )?; - - let value_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; - let value_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( - context, value_ptr, value_size, location, - )?)?; + ) + .into(), + )?; - let array_ptr = valid_block.extract_value(context, location, array_value, ptr_ty, 0)?; - let is_shared = is_shared(context, valid_block, location, array_ptr, elem_layout)?; + let is_shared = block.append_op_result(scf::r#if( + ptr_is_null, + &[IntegerType::new(context, 1).into()], + { + let region = Region::new(); + let block = region.append_block(Block::new(&[])); - let data_ptr = { - let offset_elems = if REVERSE { - valid_block.append_op_result(arith::subi(array_end, extract_len_value, location))? - } else { - array_start - }; + let k0 = block.const_int(context, location, 0, 1)?; - let offset = valid_block.append_op_result(arith::extui( - offset_elems, - IntegerType::new(context, 64).into(), - location, - ))?; - let elem_stride = - valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; - let offset = - valid_block.append_op_result(arith::muli(offset, elem_stride, location))?; + block.append_operation(scf::r#yield(&[k0], location)); + region + }, + { + let region = Region::new(); + let block = region.append_block(Block::new(&[])); - valid_block.gep( + let array_ptr = block.load( context, location, - array_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )? - }; - - let new_array_ptr = valid_block.append_op_result(scf::r#if( - is_shared, - &[ptr_ty], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let k0 = block.const_int(context, location, 0, 64)?; - let k1 = block.const_int_from_type(context, location, 1, len_ty)?; - - let elem_stride = - block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; - match metadata.get::() { - Some(dup_overrides_meta) if dup_overrides_meta.is_overriden(elem_ty) => { - // TODO: If extract_len is 1 there is no need for the for loop. - block.append_operation(scf::r#for( - k0, - value_size, - elem_stride, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[( - IntegerType::new(context, 64).into(), - location, - )])); - - let offset = block.argument(0)?.into(); - let source_ptr = block.gep( - context, - location, - data_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - let target_ptr = block.gep( - context, - location, - value_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - - let value = block.load(context, location, source_ptr, elem_type)?; - let values = dup_overrides_meta - .invoke_override(context, &block, location, elem_ty, value)?; - block.store(context, location, source_ptr, values.0)?; - block.store(context, location, target_ptr, values.1)?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); - } - _ => block.memcpy(context, location, data_ptr, value_ptr, value_size), - } - - let array_ptr = { - let array_len_bytes = - block.append_op_result(arith::subi(array_len, k1, location))?; - let array_len_bytes = block.append_op_result(arith::extui( - array_len_bytes, - IntegerType::new(context, 64).into(), - location, - ))?; - let array_len_bytes = block.append_op_result(arith::muli( - array_len_bytes, - elem_stride, - location, - ))?; - let array_len_bytes = block.append_op_result(arith::addi( - array_len_bytes, - block.const_int( - context, - location, - calc_refcount_offset(elem_layout), - 64, - )?, - location, - ))?; - - let clone_ptr = block.append_op_result(llvm::zero(ptr_ty, location))?; - let clone_ptr = block.append_op_result(ReallocBindingsMeta::realloc( - context, - clone_ptr, - array_len_bytes, - location, - )?)?; - block.store(context, location, clone_ptr, k1)?; - - let clone_ptr = block.gep( - context, - location, - clone_ptr, - &[GepIndex::Const(calc_refcount_offset(elem_layout) as i32)], - IntegerType::new(context, 8).into(), - )?; - - let data_ptr = { - let offset = if REVERSE { - array_start - } else { - block.addi(array_start, extract_len_value, location)? - }; - - let offset = block.append_op_result(arith::extui( - offset, - IntegerType::new(context, 64).into(), - location, - ))?; - let offset = - block.append_op_result(arith::muli(offset, elem_stride, location))?; - - block.gep( - context, - location, - array_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )? - }; - - let others_len = block.append_op_result(arith::subi( - array_len, - extract_len_value, - location, - ))?; - let others_len = block.append_op_result(arith::extui( - others_len, - IntegerType::new(context, 64).into(), - location, - ))?; - let others_size = - block.append_op_result(arith::muli(others_len, elem_stride, location))?; - - match metadata.get::() { - Some(dup_overrides_meta) => { - block.append_operation(scf::r#for( - k0, - others_size, - elem_stride, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[( - IntegerType::new(context, 64).into(), - location, - )])); - - let offset = block.argument(0)?.into(); - let source_ptr = block.gep( - context, - location, - data_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - let target_ptr = block.gep( - context, - location, - clone_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - - let value = - block.load(context, location, source_ptr, elem_type)?; - let values = dup_overrides_meta.invoke_override( - context, &block, location, elem_ty, value, - )?; - block.store(context, location, source_ptr, values.0)?; - block.store(context, location, target_ptr, values.1)?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); - } - _ => block.memcpy(context, location, data_ptr, clone_ptr, others_size), - } - - metadata - .get::() - .unwrap() - .invoke_override(context, &block, location, self_ty, array_value)?; - - clone_ptr - }; - - block.append_operation(scf::r#yield(&[array_ptr], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - block.memcpy(context, location, data_ptr, value_ptr, value_size); - - block.append_operation(scf::r#yield(&[array_ptr], location)); - region - }, - location, - ))?; - - let array_value = - valid_block.insert_value(context, location, array_value, new_array_ptr, 0)?; - - let has_realloc = valid_block.append_op_result( - ods::llvm::icmp( - context, - IntegerType::new(context, 1).into(), - array_ptr, - new_array_ptr, - IntegerAttribute::new(IntegerType::new(context, 64).into(), 1).into(), - location, - ) - .into(), - )?; - let array_value = valid_block.append_op_result(scf::r#if( - has_realloc, - &[array_value.r#type()], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let k0 = block.const_int_from_type(context, location, 0, len_ty)?; - let array_len = - block.append_op_result(arith::subi(array_len, extract_len_value, location))?; - - let array_value = block.insert_value(context, location, array_value, k0, 1)?; - let array_value = - block.insert_value(context, location, array_value, array_len, 2)?; - let array_value = - block.insert_value(context, location, array_value, array_len, 3)?; - - block.append_operation(scf::r#yield(&[array_value], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let array_value = if REVERSE { - let array_end = block.append_op_result(arith::subi( - array_end, - extract_len_value, - location, - ))?; - block.insert_value(context, location, array_value, array_end, 2)? - } else { - let array_start = block.append_op_result(arith::addi( - array_start, - extract_len_value, - location, - ))?; - block.insert_value(context, location, array_value, array_start, 1)? - }; - - block.append_operation(scf::r#yield(&[array_value], location)); - region - }, - location, - ))?; - - branch_values.push(array_value); - branch_values.push(value_ptr); - - valid_block.append_operation(helper.br(0, &branch_values, location)); - } - - { - if CONSUME { - let self_ty = match info { - PopInfo::Single(info) => &info.signature.param_signatures[0].ty, - PopInfo::Multi(info) => &info.signature.param_signatures[1].ty, - }; - - metadata - .get::() - .unwrap() - .invoke_override(context, error_block, location, self_ty, array_value)?; - } else { - branch_values.push(array_value); - } - - error_block.append_operation(helper.br(1, &branch_values, location)); - } - - Ok(()) -} - -/// Generate MLIR operations for the `array_get` libfunc. -pub fn build_get<'ctx, 'this>( - context: &'ctx Context, - registry: &ProgramRegistry, - entry: &'this Block<'ctx>, - location: Location<'ctx>, - helper: &LibfuncHelper<'ctx, 'this>, - metadata: &mut MetadataStorage, - info: &SignatureAndTypeConcreteLibfunc, -) -> Result<()> { - let ptr_ty = llvm::r#type::pointer(context, 0); - let len_ty = IntegerType::new(context, 32).into(); - - // Build the type so that the drop impl invocation works properly. - registry.build_type( - context, - helper, - metadata, - &info.signature.param_signatures[1].ty, - )?; - - let range_check = - super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; - - let array_start = - entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 1)?; - let array_end = entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 2)?; - - let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; - let is_valid = entry.append_op_result(arith::cmpi( - context, - CmpiPredicate::Ult, - entry.argument(2)?.into(), - array_len, - location, - ))?; - - let valid_block = helper.append_block(Block::new(&[])); - let error_block = helper.append_block(Block::new(&[])); - entry.append_operation(cf::cond_br( - context, - is_valid, - valid_block, - error_block, - &[], - &[], - location, - )); - - { - let (elem_ty, elem_layout) = - registry.build_type_with_layout(context, helper, metadata, &info.ty)?; - let elem_stride = - valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; - - let value_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; - let value_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( - context, - value_ptr, - elem_stride, - location, - )?)?; - - let array_ptr = - valid_block.extract_value(context, location, entry.argument(1)?.into(), ptr_ty, 0)?; - let is_shared = is_shared(context, valid_block, location, array_ptr, elem_layout)?; - - let offset = valid_block.append_op_result(arith::addi( - array_start, - entry.argument(2)?.into(), - location, - ))?; - let offset = valid_block.append_op_result(arith::extui( - offset, - IntegerType::new(context, 64).into(), - location, - ))?; - let offset = valid_block.append_op_result(arith::muli(offset, elem_stride, location))?; - - let source_ptr = valid_block.gep( - context, - location, - array_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - - valid_block.append_operation(scf::r#if( - is_shared, - &[], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - match metadata.get::() { - Some(dup_overrides_meta) if dup_overrides_meta.is_overriden(&info.ty) => { - let value = block.load(context, location, source_ptr, elem_ty)?; - let values = dup_overrides_meta - .invoke_override(context, &block, location, &info.ty, value)?; - block.store(context, location, source_ptr, values.0)?; - block.store(context, location, value_ptr, values.1)?; - } - _ => block.memcpy(context, location, source_ptr, value_ptr, elem_stride), - } - - metadata - .get::() - .unwrap() - .invoke_override( - context, - &block, - location, - &info.signature.param_signatures[1].ty, - entry.argument(1)?.into(), - )?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - block.memcpy(context, location, source_ptr, value_ptr, elem_stride); - - match metadata.get::() { - Some(drop_overrides_meta) if drop_overrides_meta.is_overriden(&info.ty) => { - let drop_loop = |o0, o1| { - block.append_operation(scf::r#for( - o0, - o1, - elem_stride, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[( - IntegerType::new(context, 64).into(), - location, - )])); - - let value_ptr = block.gep( - context, - location, - array_ptr, - &[GepIndex::Value(block.argument(0)?.into())], - IntegerType::new(context, 8).into(), - )?; - let value = - block.load(context, location, value_ptr, elem_ty)?; - drop_overrides_meta.invoke_override( - context, &block, location, &info.ty, value, - )?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); - - Result::Ok(()) - }; - - let o0 = block.append_op_result(arith::extui( - array_start, - IntegerType::new(context, 64).into(), - location, - ))?; - let o1 = block.append_op_result(arith::addi( - array_start, - entry.argument(2)?.into(), - location, - ))?; - let o1 = block.append_op_result(arith::extui( - o1, - IntegerType::new(context, 64).into(), - location, - ))?; - let o0 = block.append_op_result(arith::muli(o0, elem_stride, location))?; - let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; - drop_loop(o0, o1)?; - - let o0 = block.append_op_result(arith::addi(o1, elem_stride, location))?; - let o1 = block.append_op_result(arith::extui( - array_end, - IntegerType::new(context, 64).into(), - location, - ))?; - let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; - drop_loop(o0, o1)?; - } - _ => {} - } - - let array_ptr = block.gep( - context, - location, - array_ptr, - &[GepIndex::Const(-(calc_refcount_offset(elem_layout) as i32))], - IntegerType::new(context, 8).into(), - )?; - block.append_operation(ReallocBindingsMeta::free(context, array_ptr, location)?); - - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); - - valid_block.append_operation(helper.br(0, &[range_check, value_ptr], location)); - } - - { - metadata - .get::() - .unwrap() - .invoke_override( - context, - error_block, - location, - &info.signature.param_signatures[1].ty, - entry.argument(1)?.into(), - )?; - - error_block.append_operation(helper.br(1, &[range_check], location)); - } - - Ok(()) -} - -/// Generate MLIR operations for the `array_slice` libfunc. -pub fn build_slice<'ctx, 'this>( - context: &'ctx Context, - registry: &ProgramRegistry, - entry: &'this Block<'ctx>, - location: Location<'ctx>, - helper: &LibfuncHelper<'ctx, 'this>, - metadata: &mut MetadataStorage, - info: &SignatureAndTypeConcreteLibfunc, -) -> Result<()> { - // Signature: - // Params: RangeCheck, Snapshot>, u32, u32 - // Branches: - // 0: RangeCheck, Snapshot> - // 1: RangeCheck - - let ptr_ty = llvm::r#type::pointer(context, 0); - let len_ty = IntegerType::new(context, 32).into(); - - let self_ty = registry.build_type( - context, - helper, - metadata, - &info.signature.param_signatures[1].ty, - )?; - - let range_check = - super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; - - let k0 = entry.const_int_from_type(context, location, 0, len_ty)?; - let k1 = entry.const_int_from_type(context, location, 1, len_ty)?; - - let array_start = - entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 1)?; - let array_end = entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 2)?; - let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; - - let slice_start = entry.argument(2)?.into(); - let slice_len = entry.argument(3)?.into(); - let slice_end = entry.append_op_result(arith::addi(slice_start, slice_len, location))?; - - let slice_lhs_bound = entry.append_op_result(arith::cmpi( - context, - CmpiPredicate::Ule, - slice_start, - array_len, - location, - ))?; - let slice_rhs_bound = entry.append_op_result(arith::cmpi( - context, - CmpiPredicate::Ule, - slice_end, - array_len, - location, - ))?; - let slice_bounds = - entry.append_op_result(arith::andi(slice_lhs_bound, slice_rhs_bound, location))?; - - let valid_block = helper.append_block(Block::new(&[])); - let error_block = helper.append_block(Block::new(&[])); - entry.append_operation(cf::cond_br( - context, - slice_bounds, - valid_block, - error_block, - &[], - &[], - location, - )); - - { - let (elem_ty, elem_layout) = - registry.build_type_with_layout(context, helper, metadata, &info.ty)?; - let elem_stride = - valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; - - let slice_size = valid_block.append_op_result(arith::extui( - slice_len, - IntegerType::new(context, 64).into(), - location, - ))?; - let slice_size = - valid_block.append_op_result(arith::muli(elem_stride, slice_size, location))?; - let slice_size_with_offset = valid_block.append_op_result(arith::addi( - slice_size, - valid_block.const_int(context, location, calc_refcount_offset(elem_layout), 64)?, - location, - ))?; - - let array_ptr = - valid_block.extract_value(context, location, entry.argument(1)?.into(), ptr_ty, 0)?; - let null_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; - let is_null_source = valid_block.append_op_result( - ods::llvm::icmp( - context, - IntegerType::new(context, 1).into(), - array_ptr, - null_ptr, - IntegerAttribute::new(IntegerType::new(context, 64).into(), 0).into(), - location, - ) - .into(), - )?; - let slice_ptr = valid_block.append_op_result(scf::r#if( - is_null_source, - &[ptr_ty], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - block.append_operation(scf::r#yield(&[null_ptr], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let slice_ptr = block.append_op_result(llvm::zero(ptr_ty, location))?; - let slice_ptr = block.append_op_result(ReallocBindingsMeta::realloc( - context, - slice_ptr, - slice_size_with_offset, - location, - )?)?; - block.store(context, location, slice_ptr, k1)?; - - let slice_ptr = block.gep( - context, - location, - slice_ptr, - &[GepIndex::Const(calc_refcount_offset(elem_layout) as i32)], - IntegerType::new(context, 8).into(), - )?; - - let is_shared = is_shared(context, &block, location, array_ptr, elem_layout)?; - - let offset = - block.append_op_result(arith::addi(array_start, slice_start, location))?; - let offset = block.append_op_result(arith::extui( - offset, - IntegerType::new(context, 64).into(), - location, - ))?; - let offset = block.append_op_result(arith::muli(offset, elem_stride, location))?; - - let source_ptr = block.gep( - context, - location, - array_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - - block.append_operation(scf::r#if( - is_shared, - &[], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - match metadata.get::() { - Some(dup_overrides_meta) - if dup_overrides_meta.is_overriden(&info.ty) => - { - let k0 = block.const_int(context, location, 0, 64)?; - block.append_operation(scf::r#for( - k0, - slice_size, - elem_stride, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[( - IntegerType::new(context, 64).into(), - location, - )])); - - let offset = block.argument(0)?.into(); - let source_ptr = block.gep( - context, - location, - source_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - let target_ptr = block.gep( - context, - location, - slice_ptr, - &[GepIndex::Value(offset)], - IntegerType::new(context, 8).into(), - )?; - - let value = - block.load(context, location, source_ptr, elem_ty)?; - let values = dup_overrides_meta.invoke_override( - context, &block, location, &info.ty, value, - )?; - block.store(context, location, source_ptr, values.0)?; - block.store(context, location, target_ptr, values.1)?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); - } - _ => block.memcpy(context, location, source_ptr, slice_ptr, slice_size), - } - - metadata - .get::() - .unwrap() - .invoke_override( - context, - &block, - location, - &info.signature.param_signatures[1].ty, - entry.argument(1)?.into(), - )?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - block.memcpy(context, location, source_ptr, slice_ptr, slice_size); - - match metadata.get::() { - Some(drop_overrides_meta) - if drop_overrides_meta.is_overriden(&info.ty) => - { - let drop_loop = |o0, o1| { - block.append_operation(scf::r#for( - o0, - o1, - elem_stride, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[( - IntegerType::new(context, 64).into(), - location, - )])); - - let value_ptr = block.gep( - context, - location, - array_ptr, - &[GepIndex::Value(block.argument(0)?.into())], - IntegerType::new(context, 8).into(), - )?; - let value = block - .load(context, location, value_ptr, elem_ty)?; - drop_overrides_meta.invoke_override( - context, &block, location, &info.ty, value, - )?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); - - Result::Ok(()) - }; - - let o0 = block.append_op_result(arith::extui( - array_start, - IntegerType::new(context, 64).into(), - location, - ))?; - let o1 = block.append_op_result(arith::addi( - array_start, - slice_start, - location, - ))?; - let o1 = block.append_op_result(arith::extui( - o1, - IntegerType::new(context, 64).into(), - location, - ))?; - let o0 = block.append_op_result(arith::muli( - o0, - elem_stride, - location, - ))?; - let o1 = block.append_op_result(arith::muli( - o1, - elem_stride, - location, - ))?; - drop_loop(o0, o1)?; - - let o0 = block - .append_op_result(arith::addi(o1, slice_size, location))?; - let o1 = block.append_op_result(arith::extui( - array_end, - IntegerType::new(context, 64).into(), - location, - ))?; - let o1 = block.append_op_result(arith::muli( - o1, - elem_stride, - location, - ))?; - drop_loop(o0, o1)?; - } - _ => {} - } - - let array_ptr = block.gep( - context, - location, - array_ptr, - &[GepIndex::Const(-(calc_refcount_offset(elem_layout) as i32))], - IntegerType::new(context, 8).into(), - )?; - block.append_operation(ReallocBindingsMeta::free( - context, array_ptr, location, - )?); - - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); - - block.append_operation(scf::r#yield(&[slice_ptr], location)); - region - }, - location, - ))?; - - let slice_value = valid_block.append_op_result(llvm::undef(self_ty, location))?; - let slice_value = valid_block.insert_values( - context, - location, - slice_value, - &[slice_ptr, k0, slice_len, slice_len], - )?; - - valid_block.append_operation(helper.br(0, &[range_check, slice_value], location)); - } - - { - metadata - .get::() - .ok_or(Error::MissingMetadata)? - .invoke_override( - context, - error_block, - location, - &info.signature.param_signatures[1].ty, - entry.argument(1)?.into(), + array_ptr_ptr, + llvm::r#type::pointer(context, 0), )?; - - error_block.append_operation(helper.br(1, &[range_check], location)); - } - - Ok(()) -} - -/// Generate MLIR operations for the `array_len` libfunc. -pub fn build_len<'ctx, 'this>( - context: &'ctx Context, - _registry: &ProgramRegistry, - entry: &'this Block<'ctx>, - location: Location<'ctx>, - helper: &LibfuncHelper<'ctx, 'this>, - metadata: &mut MetadataStorage, - info: &SignatureAndTypeConcreteLibfunc, -) -> Result<()> { - let len_ty = IntegerType::new(context, 32).into(); - - let array_start = - entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 1)?; - let array_end = entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 2)?; - - let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; - - metadata - .get::() - .unwrap() - .invoke_override( - context, - entry, - location, - &info.signature.param_signatures[0].ty, - entry.argument(0)?.into(), - )?; - - entry.append_operation(helper.br(0, &[array_len], location)); - Ok(()) -} - -fn calc_refcount_offset(layout: Layout) -> usize { - get_integer_layout(32) - .align_to(layout.align()) - .unwrap() - .pad_to_align() - .size() -} - -fn is_shared<'ctx, 'this>( - context: &'ctx Context, - block: &'this Block<'ctx>, - location: Location<'ctx>, - array_ptr: Value<'ctx, 'this>, - elem_layout: Layout, -) -> Result> { - let null_ptr = - block.append_op_result(llvm::zero(llvm::r#type::pointer(context, 0), location))?; - let ptr_is_null = block.append_op_result( - ods::llvm::icmp( - context, - IntegerType::new(context, 1).into(), - array_ptr, - null_ptr, - IntegerAttribute::new(IntegerType::new(context, 64).into(), 0).into(), - location, - ) - .into(), - )?; - - let is_shared = block.append_op_result(scf::r#if( - ptr_is_null, - &[IntegerType::new(context, 1).into()], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - let k0 = block.const_int(context, location, 0, 1)?; - - block.append_operation(scf::r#yield(&[k0], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - let array_ptr = block.gep( context, location, array_ptr, - &[GepIndex::Const(-(calc_refcount_offset(elem_layout) as i32))], + &[GepIndex::Const( + -(calc_data_prefix_offset(elem_layout) as i32), + )], IntegerType::new(context, 8).into(), )?; let ref_count = block.load( diff --git a/src/types.rs b/src/types.rs index 213f90556..94c3f68d3 100644 --- a/src/types.rs +++ b/src/types.rs @@ -29,7 +29,7 @@ use num_bigint::{BigInt, Sign}; use num_traits::{Bounded, One}; use std::{alloc::Layout, error::Error, ops::Deref, sync::OnceLock}; -mod array; +pub mod array; mod bitwise; mod bounded_int; mod r#box; diff --git a/src/types/array.rs b/src/types/array.rs index 2ed55c39d..a1126203e 100644 --- a/src/types/array.rs +++ b/src/types/array.rs @@ -48,6 +48,7 @@ use melior::{ dialect::{arith::CmpiPredicate, func, scf}, ir::BlockLike, }; +use std::alloc::Layout; /// Build the MLIR type. /// @@ -112,11 +113,7 @@ fn build_dup<'ctx>( let value_ty = registry.build_type(context, module, metadata, info.self_ty())?; let elem_layout = registry.get_type(&info.ty)?.layout(registry)?; - let refcount_offset = get_integer_layout(32) - .align_to(elem_layout.align()) - .unwrap() - .pad_to_align() - .size(); + let refcount_offset = calc_data_prefix_offset(elem_layout); let region = Region::new(); let entry = region.append_block(Block::new(&[(value_ty, location)])); @@ -151,13 +148,19 @@ fn build_dup<'ctx>( let region = Region::new(); let block = region.append_block(Block::new(&[])); - let array_ptr = block.extract_value( + let array_ptr_ptr = block.extract_value( context, location, entry.argument(0)?.into(), llvm::r#type::pointer(context, 0), 0, )?; + let array_ptr = block.load( + context, + location, + array_ptr_ptr, + llvm::r#type::pointer(context, 0), + )?; let refcount_ptr = block.gep( context, @@ -166,12 +169,24 @@ fn build_dup<'ctx>( &[GepIndex::Const(-(refcount_offset as i32))], IntegerType::new(context, 8).into(), )?; + metadata + .get_mut::() + .unwrap() + .debug_print(context, module, &block, "BEFORE", location)?; + metadata + .get_mut::() + .unwrap() + .print_pointer(context, module, &block, refcount_ptr, location)?; let ref_count = block.load( context, location, refcount_ptr, IntegerType::new(context, 32).into(), )?; + metadata + .get_mut::() + .unwrap() + .debug_print(context, module, &block, "AFTER", location)?; let k1 = block.const_int(context, location, 1, 32)?; let ref_count = block.append_op_result(arith::addi(ref_count, k1, location))?; @@ -210,16 +225,12 @@ fn build_drop<'ctx>( let elem_stride = elem_ty.layout(registry)?.pad_to_align().size(); let elem_ty = elem_ty.build(context, module, registry, metadata, &info.ty)?; let elem_layout = registry.get_type(&info.ty)?.layout(registry)?; - let refcount_offset = get_integer_layout(32) - .align_to(elem_layout.align()) - .unwrap() - .pad_to_align() - .size(); + let refcount_offset = calc_data_prefix_offset(elem_layout); let region = Region::new(); let entry = region.append_block(Block::new(&[(value_ty, location)])); - let array_ptr = entry.extract_value( + let array_ptr_ptr = entry.extract_value( context, location, entry.argument(0)?.into(), @@ -263,6 +274,12 @@ fn build_drop<'ctx>( let block = region.append_block(Block::new(&[])); // obtain the reference counter + let array_ptr = block.load( + context, + location, + array_ptr_ptr, + llvm::r#type::pointer(context, 0), + )?; let refcount_ptr = block.gep( context, location, @@ -389,6 +406,12 @@ fn build_drop<'ctx>( refcount_ptr, location, )?); + block.append_operation(ReallocBindingsMeta::free( + context, + array_ptr_ptr, + location, + )?); + block.append_operation(scf::r#yield(&[], location)); region }, @@ -405,6 +428,17 @@ fn build_drop<'ctx>( Ok(region) } +pub fn calc_data_prefix_offset(layout: Layout) -> usize { + get_integer_layout(32) + .extend(get_integer_layout(32)) + .unwrap() + .0 + .align_to(layout.align()) + .unwrap() + .pad_to_align() + .size() +} + #[cfg(test)] mod test { use crate::{ diff --git a/src/values.rs b/src/values.rs index 08874046d..a80a933b1 100644 --- a/src/values.rs +++ b/src/values.rs @@ -225,26 +225,26 @@ impl Value { let elem_ty = registry.get_type(&info.ty)?; let elem_layout = elem_ty.layout(registry)?.pad_to_align(); - let refcount_offset = get_integer_layout(32) - .align_to(elem_layout.align()) - .unwrap() - .pad_to_align() - .size(); - let ptr = match elem_layout.size() * data.len() { + let refcount_offset = + crate::types::array::calc_data_prefix_offset(elem_layout); + let len: u32 = data + .len() + .try_into() + .map_err(|_| Error::IntegerConversion)?; + let ptr: *mut () = match elem_layout.size() * data.len() { 0 => std::ptr::null_mut(), - len => { - let ptr: *mut () = libc_malloc(len + refcount_offset).cast(); + data_len => { + let ptr: *mut () = libc_malloc(data_len + refcount_offset).cast(); // Write reference count. - ptr.cast::().write(1); + ptr.cast::<(u32, u32)>().write((1, len)); - ptr.byte_add(refcount_offset) + // Make double pointer. + let ptr_ptr: *mut *mut () = libc_malloc(8).cast(); + ptr_ptr.write(ptr.byte_add(refcount_offset)); + ptr_ptr.cast() } }; - let len: u32 = data - .len() - .try_into() - .map_err(|_| Error::IntegerConversion)?; // Write the data. for (idx, elem) in data.iter().enumerate() { @@ -618,11 +618,7 @@ impl Value { let data_ptr = init_data_ptr.byte_add(elem_stride * start_offset_value as usize); - let refcount_offset = get_integer_layout(32) - .align_to(elem_layout.align()) - .unwrap() - .pad_to_align() - .size(); + let refcount_offset = crate::types::array::calc_data_prefix_offset(elem_layout); let should_drop = if !init_data_ptr.is_null() && init_data_ptr.byte_sub(refcount_offset).cast::().read() == 1 { From aa2b36ea3a329e901ceb96d8856458260db6f65f Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 14 Feb 2025 13:00:03 +0100 Subject: [PATCH 02/14] More progress. --- src/libfuncs/array.rs | 692 +++++++++++++++++++++++++++--------------- src/types/array.rs | 12 - src/values.rs | 65 ++-- 3 files changed, 476 insertions(+), 293 deletions(-) diff --git a/src/libfuncs/array.rs b/src/libfuncs/array.rs index 453dd42e6..d19ab8fb5 100644 --- a/src/libfuncs/array.rs +++ b/src/libfuncs/array.rs @@ -80,16 +80,14 @@ pub fn build<'ctx, 'this>( todo!() } ArrayConcreteLibfunc::Get(info) => { - // build_get(context, registry, entry, location, helper, metadata, info) - todo!() + build_get(context, registry, entry, location, helper, metadata, info) } ArrayConcreteLibfunc::Slice(info) => { // build_slice(context, registry, entry, location, helper, metadata, info) todo!() } ArrayConcreteLibfunc::Len(info) => { - // build_len(context, registry, entry, location, helper, metadata, info) - todo!() + build_len(context, registry, entry, location, helper, metadata, info) } ArrayConcreteLibfunc::SnapshotPopFront(info) => { // build_pop::( @@ -525,13 +523,6 @@ pub fn build_append<'ctx, 'this>( let (_, elem_layout) = registry.build_type_with_layout(context, helper, metadata, &info.ty)?; let elem_stride = entry.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; - // If is_empty - // - Allocate initial space. - // Else if it has no space - // - Reallocate - // - // Push item. - fn compute_next_capacity<'ctx, 'this>( context: &'ctx Context, block: &'this Block<'ctx>, @@ -578,8 +569,9 @@ pub fn build_append<'ctx, 'this>( let (array_capacity, realloc_len) = compute_next_capacity(context, &block, location, elem_stride, array_capacity)?; - let data_prefix_size = block.const_int(context, location, data_prefix_size, 64)?; - let realloc_len = block.addi(realloc_len, data_prefix_size, location)?; + let data_prefix_size_value = + block.const_int(context, location, data_prefix_size, 64)?; + let realloc_len = block.addi(realloc_len, data_prefix_size_value, location)?; let null_ptr = block.append_op_result(llvm::zero(ptr_ty, location))?; let array_ptr = block.append_op_result(ReallocBindingsMeta::realloc( @@ -589,6 +581,25 @@ pub fn build_append<'ctx, 'this>( location, )?)?; + let k1 = block.const_int_from_type(context, location, 1, len_ty)?; + block.store(context, location, array_ptr, k1)?; + let max_len_ptr = block.gep( + context, + location, + array_ptr, + &[GepIndex::Const(4)], + IntegerType::new(context, 8).into(), + )?; + block.store(context, location, max_len_ptr, k0)?; + + let array_ptr = block.gep( + context, + location, + array_ptr, + &[GepIndex::Const(data_prefix_size as i32)], + IntegerType::new(context, 8).into(), + )?; + let k8 = block.const_int(context, location, 8, 64)?; let array_ptr_ptr = block.append_op_result(ReallocBindingsMeta::realloc( context, null_ptr, k8, location, @@ -636,9 +647,9 @@ pub fn build_append<'ctx, 'this>( array_capacity, )?; - let data_prefix_size = + let data_prefix_size_value = block.const_int(context, location, data_prefix_size, 64)?; - let realloc_len = block.addi(realloc_len, data_prefix_size, location)?; + let realloc_len = block.addi(realloc_len, data_prefix_size_value, location)?; let array_ptr_ptr = block.extract_value( context, @@ -648,12 +659,28 @@ pub fn build_append<'ctx, 'this>( 0, )?; let array_ptr = block.load(context, location, array_ptr_ptr, ptr_ty)?; + let array_ptr = block.gep( + context, + location, + array_ptr, + &[GepIndex::Const(-(data_prefix_size as i32))], + IntegerType::new(context, 8).into(), + )?; + let array_ptr = block.append_op_result(ReallocBindingsMeta::realloc( context, array_ptr, realloc_len, location, )?)?; + let array_ptr = block.gep( + context, + location, + array_ptr, + &[GepIndex::Const(data_prefix_size as i32)], + IntegerType::new(context, 8).into(), + )?; + block.store(context, location, array_ptr_ptr, array_ptr)?; let array_obj = block.insert_value( @@ -695,10 +722,173 @@ pub fn build_append<'ctx, 'this>( entry.store(context, location, target_ptr, entry.argument(1)?.into())?; + // TODO: Update max length. + let k1 = entry.const_int_from_type(context, location, 1, len_ty)?; + let array_end = entry.extract_value(context, location, array_obj, len_ty, 2)?; + let array_end = entry.addi(array_end, k1, location)?; + let array_obj = entry.insert_value(context, location, array_obj, array_end, 2)?; + entry.append_operation(helper.br(0, &[array_obj], location)); Ok(()) } +#[derive(Clone, Copy)] +enum PopInfo<'a> { + Single(&'a SignatureAndTypeConcreteLibfunc), + Multi(&'a ConcreteMultiPopLibfunc), +} + +/// Generate MLIR operations for the `array_pop_*` libfuncs. +/// +/// Template arguments: +/// - Consume: Whether to consume or not the array on failure. +/// - Reverse: False for front-popping, true for back-popping. +/// +/// The `info` argument contains how many items to pop. +fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: PopInfo, +) -> Result<()> { + metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, helper)); + + let ptr_ty = llvm::r#type::pointer(context, 0); + let len_ty = IntegerType::new(context, 32).into(); + + let (self_ty, elem_ty, array_obj, extract_len, branch_values) = match info { + PopInfo::Single(info) => ( + &info.signature.param_signatures[0].ty, + &info.ty, + entry.argument(0)?.into(), + 1, + Vec::new(), + ), + PopInfo::Multi(ConcreteMultiPopLibfunc { + popped_ty, + signature, + }) => { + let range_check = super::increment_builtin_counter( + context, + entry, + location, + entry.argument(0)?.into(), + )?; + + let CoreTypeConcrete::Snapshot(InfoAndTypeConcreteType { ty, .. }) = + registry.get_type(&signature.param_signatures[1].ty)? + else { + return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); + }; + + let CoreTypeConcrete::Array(InfoAndTypeConcreteType { ty, .. }) = + registry.get_type(ty)? + else { + return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); + }; + + let CoreTypeConcrete::Struct(info) = registry.get_type(popped_ty)? else { + return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); + }; + debug_assert!(info.members.iter().all(|member_ty| member_ty == ty)); + + ( + &signature.param_signatures[1].ty, + ty, + entry.argument(1)?.into(), + info.members.len(), + vec![range_check], + ) + } + }; + + let array_start = entry.extract_value(context, location, array_obj, len_ty, 1)?; + let array_end = entry.extract_value(context, location, array_obj, len_ty, 2)?; + + let extract_len_value = entry.const_int_from_type(context, location, extract_len, len_ty)?; + let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; + let has_enough_data = entry.cmpi( + context, + CmpiPredicate::Ule, + extract_len_value, + array_len, + location, + )?; + + let valid_block = helper.append_block(Block::new(&[])); + let error_block = helper.append_block(Block::new(&[])); + entry.append_operation(cf::cond_br( + context, + has_enough_data, + valid_block, + error_block, + &[], + &[], + location, + )); + + { + let mut branch_values = branch_values.clone(); + + // TODO: Get pointer of items to extract. + // TODO: Update bounds. + // TODO: Clone items to extract. + + let array_ptr_ptr = valid_block.extract_value(context, location, array_obj, ptr_ty, 0)?; + let array_ptr = valid_block.load(context, location, array_ptr_ptr, ptr_ty)?; + + let (array_obj, data_ptr) = if REVERSE { + let array_end = valid_block.append_op_result(arith::subi( + array_end, + extract_len_value, + location, + ))?; + let array_obj = valid_block.insert_value(context, location, array_obj, array_end, 2)?; + + // TODO: Compute data offset: elem_stride * array_end. + // TODO: GEP array_ptr. + + (array_obj, data_ptr) + } else { + // TODO: Compute data offset: elem_stride * array_end. + // TODO: GEP array_ptr. + + let array_start = valid_block.append_op_result(arith::addi( + array_start, + extract_len_value, + location, + ))?; + let array_obj = + valid_block.insert_value(context, location, array_obj, array_start, 1)?; + + (array_obj, data_ptr) + }; + + // TODO: Clone items out of the array. + // TODO: Branch out. + } + + { + let mut branch_values = branch_values.clone(); + + if CONSUME { + metadata + .get::() + .unwrap() + .invoke_override(context, error_block, location, self_ty, array_obj)?; + } else { + branch_values.push(array_obj); + } + + error_block.append_operation(helper.br(1, &branch_values, location)); + } + + Ok(()) +} + // /// Generate MLIR operations for the `array_pop_*` libfuncs. // /// // /// Template arguments: @@ -937,235 +1127,235 @@ pub fn build_append<'ctx, 'this>( // Ok(()) // } -// /// Generate MLIR operations for the `array_get` libfunc. -// pub fn build_get<'ctx, 'this>( -// context: &'ctx Context, -// registry: &ProgramRegistry, -// entry: &'this Block<'ctx>, -// location: Location<'ctx>, -// helper: &LibfuncHelper<'ctx, 'this>, -// metadata: &mut MetadataStorage, -// info: &SignatureAndTypeConcreteLibfunc, -// ) -> Result<()> { -// let ptr_ty = llvm::r#type::pointer(context, 0); -// let len_ty = IntegerType::new(context, 32).into(); - -// // Build the type so that the drop impl invocation works properly. -// registry.build_type( -// context, -// helper, -// metadata, -// &info.signature.param_signatures[1].ty, -// )?; +/// Generate MLIR operations for the `array_get` libfunc. +pub fn build_get<'ctx, 'this>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + let ptr_ty = llvm::r#type::pointer(context, 0); + let len_ty = IntegerType::new(context, 32).into(); -// let range_check = -// super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; + // Build the type so that the drop impl invocation works properly. + registry.build_type( + context, + helper, + metadata, + &info.signature.param_signatures[1].ty, + )?; -// let array_start = -// entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 1)?; -// let array_end = entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 2)?; + let range_check = + super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; -// let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; -// let is_valid = entry.append_op_result(arith::cmpi( -// context, -// CmpiPredicate::Ult, -// entry.argument(2)?.into(), -// array_len, -// location, -// ))?; + let array_start = + entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 1)?; + let array_end = entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 2)?; -// let valid_block = helper.append_block(Block::new(&[])); -// let error_block = helper.append_block(Block::new(&[])); -// entry.append_operation(cf::cond_br( -// context, -// is_valid, -// valid_block, -// error_block, -// &[], -// &[], -// location, -// )); + let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; + let is_valid = entry.append_op_result(arith::cmpi( + context, + CmpiPredicate::Ult, + entry.argument(2)?.into(), + array_len, + location, + ))?; -// { -// let (elem_ty, elem_layout) = -// registry.build_type_with_layout(context, helper, metadata, &info.ty)?; -// let elem_stride = -// valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; + let valid_block = helper.append_block(Block::new(&[])); + let error_block = helper.append_block(Block::new(&[])); + entry.append_operation(cf::cond_br( + context, + is_valid, + valid_block, + error_block, + &[], + &[], + location, + )); -// let value_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; -// let value_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( -// context, -// value_ptr, -// elem_stride, -// location, -// )?)?; + { + let (elem_ty, elem_layout) = + registry.build_type_with_layout(context, helper, metadata, &info.ty)?; + let elem_stride = + valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; -// let array_ptr = -// valid_block.extract_value(context, location, entry.argument(1)?.into(), ptr_ty, 0)?; -// let is_shared = is_shared(context, valid_block, location, array_ptr, elem_layout)?; + let value_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; + let value_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( + context, + value_ptr, + elem_stride, + location, + )?)?; -// let offset = valid_block.append_op_result(arith::addi( -// array_start, -// entry.argument(2)?.into(), -// location, -// ))?; -// let offset = valid_block.append_op_result(arith::extui( -// offset, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let offset = valid_block.append_op_result(arith::muli(offset, elem_stride, location))?; + let array_ptr = + valid_block.extract_value(context, location, entry.argument(1)?.into(), ptr_ty, 0)?; + let is_shared = is_shared(context, valid_block, location, array_ptr, elem_layout)?; -// let source_ptr = valid_block.gep( -// context, -// location, -// array_ptr, -// &[GepIndex::Value(offset)], -// IntegerType::new(context, 8).into(), -// )?; + let offset = valid_block.append_op_result(arith::addi( + array_start, + entry.argument(2)?.into(), + location, + ))?; + let offset = valid_block.append_op_result(arith::extui( + offset, + IntegerType::new(context, 64).into(), + location, + ))?; + let offset = valid_block.append_op_result(arith::muli(offset, elem_stride, location))?; -// valid_block.append_operation(scf::r#if( -// is_shared, -// &[], -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[])); + let source_ptr = valid_block.gep( + context, + location, + array_ptr, + &[GepIndex::Value(offset)], + IntegerType::new(context, 8).into(), + )?; -// match metadata.get::() { -// Some(dup_overrides_meta) if dup_overrides_meta.is_overriden(&info.ty) => { -// let value = block.load(context, location, source_ptr, elem_ty)?; -// let values = dup_overrides_meta -// .invoke_override(context, &block, location, &info.ty, value)?; -// block.store(context, location, source_ptr, values.0)?; -// block.store(context, location, value_ptr, values.1)?; -// } -// _ => block.memcpy(context, location, source_ptr, value_ptr, elem_stride), -// } - -// metadata -// .get::() -// .unwrap() -// .invoke_override( -// context, -// &block, -// location, -// &info.signature.param_signatures[1].ty, -// entry.argument(1)?.into(), -// )?; + valid_block.append_operation(scf::r#if( + is_shared, + &[], + { + let region = Region::new(); + let block = region.append_block(Block::new(&[])); -// block.append_operation(scf::r#yield(&[], location)); -// region -// }, -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[])); + match metadata.get::() { + Some(dup_overrides_meta) if dup_overrides_meta.is_overriden(&info.ty) => { + let value = block.load(context, location, source_ptr, elem_ty)?; + let values = dup_overrides_meta + .invoke_override(context, &block, location, &info.ty, value)?; + block.store(context, location, source_ptr, values.0)?; + block.store(context, location, value_ptr, values.1)?; + } + _ => block.memcpy(context, location, source_ptr, value_ptr, elem_stride), + } -// block.memcpy(context, location, source_ptr, value_ptr, elem_stride); - -// match metadata.get::() { -// Some(drop_overrides_meta) if drop_overrides_meta.is_overriden(&info.ty) => { -// let drop_loop = |o0, o1| { -// block.append_operation(scf::r#for( -// o0, -// o1, -// elem_stride, -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[( -// IntegerType::new(context, 64).into(), -// location, -// )])); + metadata + .get::() + .unwrap() + .invoke_override( + context, + &block, + location, + &info.signature.param_signatures[1].ty, + entry.argument(1)?.into(), + )?; -// let value_ptr = block.gep( -// context, -// location, -// array_ptr, -// &[GepIndex::Value(block.argument(0)?.into())], -// IntegerType::new(context, 8).into(), -// )?; -// let value = -// block.load(context, location, value_ptr, elem_ty)?; -// drop_overrides_meta.invoke_override( -// context, &block, location, &info.ty, value, -// )?; - -// block.append_operation(scf::r#yield(&[], location)); -// region -// }, -// location, -// )); + block.append_operation(scf::r#yield(&[], location)); + region + }, + { + let region = Region::new(); + let block = region.append_block(Block::new(&[])); -// Result::Ok(()) -// }; + block.memcpy(context, location, source_ptr, value_ptr, elem_stride); + + match metadata.get::() { + Some(drop_overrides_meta) if drop_overrides_meta.is_overriden(&info.ty) => { + let drop_loop = |o0, o1| { + block.append_operation(scf::r#for( + o0, + o1, + elem_stride, + { + let region = Region::new(); + let block = region.append_block(Block::new(&[( + IntegerType::new(context, 64).into(), + location, + )])); + + let value_ptr = block.gep( + context, + location, + array_ptr, + &[GepIndex::Value(block.argument(0)?.into())], + IntegerType::new(context, 8).into(), + )?; + let value = + block.load(context, location, value_ptr, elem_ty)?; + drop_overrides_meta.invoke_override( + context, &block, location, &info.ty, value, + )?; + + block.append_operation(scf::r#yield(&[], location)); + region + }, + location, + )); + + Result::Ok(()) + }; + + let o0 = block.append_op_result(arith::extui( + array_start, + IntegerType::new(context, 64).into(), + location, + ))?; + let o1 = block.append_op_result(arith::addi( + array_start, + entry.argument(2)?.into(), + location, + ))?; + let o1 = block.append_op_result(arith::extui( + o1, + IntegerType::new(context, 64).into(), + location, + ))?; + let o0 = block.append_op_result(arith::muli(o0, elem_stride, location))?; + let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; + drop_loop(o0, o1)?; + + let o0 = block.append_op_result(arith::addi(o1, elem_stride, location))?; + let o1 = block.append_op_result(arith::extui( + array_end, + IntegerType::new(context, 64).into(), + location, + ))?; + let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; + drop_loop(o0, o1)?; + } + _ => {} + } -// let o0 = block.append_op_result(arith::extui( -// array_start, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let o1 = block.append_op_result(arith::addi( -// array_start, -// entry.argument(2)?.into(), -// location, -// ))?; -// let o1 = block.append_op_result(arith::extui( -// o1, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let o0 = block.append_op_result(arith::muli(o0, elem_stride, location))?; -// let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; -// drop_loop(o0, o1)?; - -// let o0 = block.append_op_result(arith::addi(o1, elem_stride, location))?; -// let o1 = block.append_op_result(arith::extui( -// array_end, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; -// drop_loop(o0, o1)?; -// } -// _ => {} -// } - -// let array_ptr = block.gep( -// context, -// location, -// array_ptr, -// &[GepIndex::Const( -// -(calc_data_prefix_offset(elem_layout) as i32), -// )], -// IntegerType::new(context, 8).into(), -// )?; -// block.append_operation(ReallocBindingsMeta::free(context, array_ptr, location)?); + let array_ptr = block.gep( + context, + location, + array_ptr, + &[GepIndex::Const( + -(calc_data_prefix_offset(elem_layout) as i32), + )], + IntegerType::new(context, 8).into(), + )?; + block.append_operation(ReallocBindingsMeta::free(context, array_ptr, location)?); -// block.append_operation(scf::r#yield(&[], location)); -// region -// }, -// location, -// )); + block.append_operation(scf::r#yield(&[], location)); + region + }, + location, + )); -// valid_block.append_operation(helper.br(0, &[range_check, value_ptr], location)); -// } + valid_block.append_operation(helper.br(0, &[range_check, value_ptr], location)); + } -// { -// metadata -// .get::() -// .unwrap() -// .invoke_override( -// context, -// error_block, -// location, -// &info.signature.param_signatures[1].ty, -// entry.argument(1)?.into(), -// )?; + { + metadata + .get::() + .unwrap() + .invoke_override( + context, + error_block, + location, + &info.signature.param_signatures[1].ty, + entry.argument(1)?.into(), + )?; -// error_block.append_operation(helper.br(1, &[range_check], location)); -// } + error_block.append_operation(helper.br(1, &[range_check], location)); + } -// Ok(()) -// } + Ok(()) +} // /// Generate MLIR operations for the `array_slice` libfunc. // pub fn build_slice<'ctx, 'this>( @@ -1532,38 +1722,38 @@ pub fn build_append<'ctx, 'this>( // Ok(()) // } -// /// Generate MLIR operations for the `array_len` libfunc. -// pub fn build_len<'ctx, 'this>( -// context: &'ctx Context, -// _registry: &ProgramRegistry, -// entry: &'this Block<'ctx>, -// location: Location<'ctx>, -// helper: &LibfuncHelper<'ctx, 'this>, -// metadata: &mut MetadataStorage, -// info: &SignatureAndTypeConcreteLibfunc, -// ) -> Result<()> { -// let len_ty = IntegerType::new(context, 32).into(); +/// Generate MLIR operations for the `array_len` libfunc. +pub fn build_len<'ctx, 'this>( + context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + let len_ty = IntegerType::new(context, 32).into(); -// let array_start = -// entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 1)?; -// let array_end = entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 2)?; + let array_start = + entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 1)?; + let array_end = entry.extract_value(context, location, entry.argument(0)?.into(), len_ty, 2)?; -// let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; + let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; -// metadata -// .get::() -// .unwrap() -// .invoke_override( -// context, -// entry, -// location, -// &info.signature.param_signatures[0].ty, -// entry.argument(0)?.into(), -// )?; + metadata + .get::() + .unwrap() + .invoke_override( + context, + entry, + location, + &info.signature.param_signatures[0].ty, + entry.argument(0)?.into(), + )?; -// entry.append_operation(helper.br(0, &[array_len], location)); -// Ok(()) -// } + entry.append_operation(helper.br(0, &[array_len], location)); + Ok(()) +} fn is_shared<'ctx, 'this>( context: &'ctx Context, diff --git a/src/types/array.rs b/src/types/array.rs index a1126203e..a63559113 100644 --- a/src/types/array.rs +++ b/src/types/array.rs @@ -169,24 +169,12 @@ fn build_dup<'ctx>( &[GepIndex::Const(-(refcount_offset as i32))], IntegerType::new(context, 8).into(), )?; - metadata - .get_mut::() - .unwrap() - .debug_print(context, module, &block, "BEFORE", location)?; - metadata - .get_mut::() - .unwrap() - .print_pointer(context, module, &block, refcount_ptr, location)?; let ref_count = block.load( context, location, refcount_ptr, IntegerType::new(context, 32).into(), )?; - metadata - .get_mut::() - .unwrap() - .debug_print(context, module, &block, "AFTER", location)?; let k1 = block.const_int(context, location, 1, 32)?; let ref_count = block.append_op_result(arith::addi(ref_count, k1, location))?; diff --git a/src/values.rs b/src/values.rs index a80a933b1..737ed274c 100644 --- a/src/values.rs +++ b/src/values.rs @@ -231,18 +231,16 @@ impl Value { .len() .try_into() .map_err(|_| Error::IntegerConversion)?; - let ptr: *mut () = match elem_layout.size() * data.len() { + let ptr: *mut () = match len { 0 => std::ptr::null_mut(), - data_len => { - let ptr: *mut () = libc_malloc(data_len + refcount_offset).cast(); + _ => { + let ptr: *mut () = + libc_malloc(elem_layout.size() * data.len() + refcount_offset) + .cast(); // Write reference count. ptr.cast::<(u32, u32)>().write((1, len)); - - // Make double pointer. - let ptr_ptr: *mut *mut () = libc_malloc(8).cast(); - ptr_ptr.write(ptr.byte_add(refcount_offset)); - ptr_ptr.cast() + ptr.byte_add(refcount_offset).cast() } }; @@ -258,6 +256,15 @@ impl Value { ); } + // Make double pointer. + let ptr_ptr = if ptr.is_null() { + null_mut() + } else { + let ptr_ptr: *mut *mut () = libc_malloc(8).cast(); + ptr_ptr.write(ptr); + ptr_ptr + }; + let target = arena .alloc_layout( Layout::new::<*mut ()>() // ptr @@ -271,7 +278,7 @@ impl Value { ) .as_ptr(); - *target.cast::<*mut ()>() = ptr; + *target.cast::<*mut ()>() = ptr_ptr.cast(); let (layout, offset) = Layout::new::<*mut NonNull<()>>().extend(Layout::new::())?; @@ -614,25 +621,20 @@ impl Value { .as_ref(); // This pointer can be null if the array is empty. - let init_data_ptr = *ptr.cast::<*mut ()>().as_ref(); - let data_ptr = - init_data_ptr.byte_add(elem_stride * start_offset_value as usize); + let array_ptr_ptr = *ptr.cast::<*mut *mut ()>().as_ref(); let refcount_offset = crate::types::array::calc_data_prefix_offset(elem_layout); - let should_drop = if !init_data_ptr.is_null() - && init_data_ptr.byte_sub(refcount_offset).cast::().read() == 1 - { - should_drop + let (should_drop, array_ptr) = if array_ptr_ptr.is_null() { + (false, null_mut()) } else { - if !init_data_ptr.is_null() && should_drop { - *init_data_ptr - .byte_sub(refcount_offset) - .cast::() - .as_mut() - .unwrap() -= 1; - } - - false + let array_ptr = array_ptr_ptr.read(); + let ref_count = dbg!(array_ptr.byte_sub(refcount_offset)) + .cast::() + .as_mut() + .unwrap(); + *ref_count -= 1; + + (*ref_count == 0, array_ptr) }; native_assert!( @@ -640,15 +642,17 @@ impl Value { "can't have an array with negative length" ); let num_elems = (end_offset_value - start_offset_value) as usize; - let mut array_value = Vec::with_capacity(num_elems); + // TODO: Drop prefix elements. + // TODO: Drop suffix elements. + + let mut array_value = Vec::with_capacity(num_elems); for i in 0..num_elems { // safe to create a NonNull because if the array has elements, the init_data_ptr can't be null. - let cur_elem_ptr = NonNull::new(data_ptr.byte_add(elem_stride * i)) + let cur_elem_ptr = NonNull::new(array_ptr.byte_add(elem_stride * i)) .to_native_assert_error( "tried to make a non-null ptr out of a null one", )?; - array_value.push(Self::from_ptr( cur_elem_ptr, &info.ty, @@ -657,8 +661,9 @@ impl Value { )?); } - if should_drop && !init_data_ptr.is_null() { - libc_free(init_data_ptr.byte_sub(refcount_offset).cast()); + if should_drop { + libc_free(array_ptr.byte_sub(refcount_offset).cast()); + libc_free(array_ptr_ptr.cast()); } Self::Array(array_value) From fbe1935b8a5bae1a00a179f11fd6de6c13ccde39 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 14 Feb 2025 13:45:15 +0100 Subject: [PATCH 03/14] Implement `array_pop_*`. --- src/libfuncs/array.rs | 223 ++++++++++++++++++++++++++---------------- 1 file changed, 140 insertions(+), 83 deletions(-) diff --git a/src/libfuncs/array.rs b/src/libfuncs/array.rs index d19ab8fb5..549ac0de4 100644 --- a/src/libfuncs/array.rs +++ b/src/libfuncs/array.rs @@ -55,30 +55,24 @@ pub fn build<'ctx, 'this>( ArrayConcreteLibfunc::Append(info) => { build_append(context, registry, entry, location, helper, metadata, info) } - ArrayConcreteLibfunc::PopFront(info) => { - // build_pop::( - // context, - // registry, - // entry, - // location, - // helper, - // metadata, - // PopInfo::Single(info), - // ) - todo!() - } - ArrayConcreteLibfunc::PopFrontConsume(info) => { - // build_pop::( - // context, - // registry, - // entry, - // location, - // helper, - // metadata, - // PopInfo::Single(info), - // ) - todo!() - } + ArrayConcreteLibfunc::PopFront(info) => build_pop::( + context, + registry, + entry, + location, + helper, + metadata, + PopInfo::Single(info), + ), + ArrayConcreteLibfunc::PopFrontConsume(info) => build_pop::( + context, + registry, + entry, + location, + helper, + metadata, + PopInfo::Single(info), + ), ArrayConcreteLibfunc::Get(info) => { build_get(context, registry, entry, location, helper, metadata, info) } @@ -89,54 +83,42 @@ pub fn build<'ctx, 'this>( ArrayConcreteLibfunc::Len(info) => { build_len(context, registry, entry, location, helper, metadata, info) } - ArrayConcreteLibfunc::SnapshotPopFront(info) => { - // build_pop::( - // context, - // registry, - // entry, - // location, - // helper, - // metadata, - // PopInfo::Single(info), - // ) - todo!() - } - ArrayConcreteLibfunc::SnapshotPopBack(info) => { - // build_pop::( - // context, - // registry, - // entry, - // location, - // helper, - // metadata, - // PopInfo::Single(info), - // ), - todo!() - } - ArrayConcreteLibfunc::SnapshotMultiPopFront(info) => { - // build_pop::( - // context, - // registry, - // entry, - // location, - // helper, - // metadata, - // PopInfo::Multi(info), - // ), - todo!() - } - ArrayConcreteLibfunc::SnapshotMultiPopBack(info) => { - // build_pop::( - // context, - // registry, - // entry, - // location, - // helper, - // metadata, - // PopInfo::Multi(info), - // ), - todo!() - } + ArrayConcreteLibfunc::SnapshotPopFront(info) => build_pop::( + context, + registry, + entry, + location, + helper, + metadata, + PopInfo::Single(info), + ), + ArrayConcreteLibfunc::SnapshotPopBack(info) => build_pop::( + context, + registry, + entry, + location, + helper, + metadata, + PopInfo::Single(info), + ), + ArrayConcreteLibfunc::SnapshotMultiPopFront(info) => build_pop::( + context, + registry, + entry, + location, + helper, + metadata, + PopInfo::Multi(info), + ), + ArrayConcreteLibfunc::SnapshotMultiPopBack(info) => build_pop::( + context, + registry, + entry, + location, + helper, + metadata, + PopInfo::Multi(info), + ), } } @@ -804,6 +786,8 @@ fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( ) } }; + let (elem_type, elem_layout) = + registry.build_type_with_layout(context, helper, metadata, elem_ty)?; let array_start = entry.extract_value(context, location, array_obj, len_ty, 1)?; let array_end = entry.extract_value(context, location, array_obj, len_ty, 2)?; @@ -833,14 +817,14 @@ fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( { let mut branch_values = branch_values.clone(); - // TODO: Get pointer of items to extract. - // TODO: Update bounds. - // TODO: Clone items to extract. - let array_ptr_ptr = valid_block.extract_value(context, location, array_obj, ptr_ty, 0)?; let array_ptr = valid_block.load(context, location, array_ptr_ptr, ptr_ty)?; - let (array_obj, data_ptr) = if REVERSE { + let elem_stride = + valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; + + // Extract pointer and update bounds. + let (array_obj, source_ptr) = if REVERSE { let array_end = valid_block.append_op_result(arith::subi( array_end, extract_len_value, @@ -848,13 +832,31 @@ fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( ))?; let array_obj = valid_block.insert_value(context, location, array_obj, array_end, 2)?; - // TODO: Compute data offset: elem_stride * array_end. - // TODO: GEP array_ptr. + // Compute data offset (elem_stride * array_end) and GEP. + let data_offset = + valid_block.extui(array_end, IntegerType::new(context, 64).into(), location)?; + let data_offset = valid_block.muli(elem_stride, data_offset, location)?; + let data_ptr = valid_block.gep( + context, + location, + array_ptr, + &[GepIndex::Value(data_offset)], + IntegerType::new(context, 8).into(), + )?; (array_obj, data_ptr) } else { - // TODO: Compute data offset: elem_stride * array_end. - // TODO: GEP array_ptr. + // Compute data offset (elem_stride * array_end) and GEP. + let data_offset = + valid_block.extui(array_start, IntegerType::new(context, 64).into(), location)?; + let data_offset = valid_block.muli(elem_stride, data_offset, location)?; + let data_ptr = valid_block.gep( + context, + location, + array_ptr, + &[GepIndex::Value(data_offset)], + IntegerType::new(context, 64).into(), + )?; let array_start = valid_block.append_op_result(arith::addi( array_start, @@ -867,8 +869,63 @@ fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( (array_obj, data_ptr) }; - // TODO: Clone items out of the array. - // TODO: Branch out. + // Allocate output pointer. + let target_size = valid_block.const_int( + context, + location, + elem_layout.pad_to_align().size() * extract_len, + 64, + )?; + let target_ptr = valid_block + .append_op_result(llvm::zero(llvm::r#type::pointer(context, 0), location))?; + let target_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( + context, + target_ptr, + target_size, + location, + )?)?; + + // Clone popped items. + match metadata.get::() { + Some(dup_overrides_meta) if dup_overrides_meta.is_overriden(elem_ty) => { + for i in 0..extract_len { + let source_ptr = valid_block.gep( + context, + location, + source_ptr, + &[GepIndex::Const( + (elem_layout.pad_to_align().size() * i) as i32, + )], + IntegerType::new(context, 8).into(), + )?; + let target_ptr = valid_block.gep( + context, + location, + target_ptr, + &[GepIndex::Const( + (elem_layout.pad_to_align().size() * i) as i32, + )], + IntegerType::new(context, 8).into(), + )?; + + let value = valid_block.load(context, location, source_ptr, elem_type)?; + let values = dup_overrides_meta.invoke_override( + context, + valid_block, + location, + elem_ty, + value, + )?; + valid_block.store(context, location, source_ptr, values.0)?; + valid_block.store(context, location, target_ptr, values.1)?; + } + } + _ => valid_block.memcpy(context, location, source_ptr, target_ptr, target_size), + } + + branch_values.push(array_obj); + branch_values.push(target_ptr); + valid_block.append_operation(helper.br(0, &branch_values, location)); } { From 11070f1cf40a5fd4f1e6aa800b5f494411e63c5f Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 14 Feb 2025 15:27:00 +0100 Subject: [PATCH 04/14] Some fixes. --- src/libfuncs/array.rs | 831 +++++------------------------------------- src/values.rs | 11 +- 2 files changed, 88 insertions(+), 754 deletions(-) diff --git a/src/libfuncs/array.rs b/src/libfuncs/array.rs index 549ac0de4..46a383be9 100644 --- a/src/libfuncs/array.rs +++ b/src/libfuncs/array.rs @@ -8,7 +8,7 @@ use crate::{ realloc_bindings::ReallocBindingsMeta, MetadataStorage, }, types::array::calc_data_prefix_offset, - utils::{get_integer_layout, BlockExt, GepIndex, ProgramRegistryExt}, + utils::{BlockExt, GepIndex, ProgramRegistryExt}, }; use cairo_lang_sierra::{ extensions::{ @@ -25,8 +25,7 @@ use melior::{ cf, llvm, ods, scf, }, ir::{ - attribute::IntegerAttribute, r#type::IntegerType, Block, BlockLike, Location, Region, - Value, ValueLike, + attribute::IntegerAttribute, r#type::IntegerType, Block, BlockLike, Location, Region, Value, }, Context, }; @@ -212,7 +211,7 @@ pub fn build_span_from_tuple<'ctx, 'this>( // Write the array data prefix. let data_prefix = entry.append_op_result(llvm::undef( - llvm::r#type::r#struct(context, &[], false), + llvm::r#type::r#struct(context, &[len_ty, len_ty], false), location, ))?; let data_prefix = entry.insert_values(context, location, data_prefix, &[k1, array_len])?; @@ -855,7 +854,7 @@ fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( location, array_ptr, &[GepIndex::Value(data_offset)], - IntegerType::new(context, 64).into(), + IntegerType::new(context, 8).into(), )?; let array_start = valid_block.append_op_result(arith::addi( @@ -946,244 +945,6 @@ fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( Ok(()) } -// /// Generate MLIR operations for the `array_pop_*` libfuncs. -// /// -// /// Template arguments: -// /// - Consume: Whether to consume or not the array on failure. -// /// - Reverse: False for front-popping, true for back-popping. -// /// -// /// The `info` argument contains how many items to pop. -// fn build_pop<'ctx, 'this, const CONSUME: bool, const REVERSE: bool>( -// context: &'ctx Context, -// registry: &ProgramRegistry, -// entry: &'this Block<'ctx>, -// location: Location<'ctx>, -// helper: &LibfuncHelper<'ctx, 'this>, -// metadata: &mut MetadataStorage, -// info: PopInfo, -// ) -> Result<()> { -// /* -// * 1. Check if there's enough data to pop. -// * 2. If there is not enough data, maybe consume and return. -// * 3. Allocate output. -// * 4. Clone or copy the popped data. -// * - Clone if shared. -// * - Copy if not shared. -// */ -// metadata.get_or_insert_with(|| ReallocBindingsMeta::new(context, helper)); - -// let ptr_ty = llvm::r#type::pointer(context, 0); -// let len_ty = IntegerType::new(context, 32).into(); - -// let (self_ty, elem_ty, array_value, extract_len, mut branch_values) = match info { -// PopInfo::Single(info) => ( -// &info.signature.param_signatures[0].ty, -// &info.ty, -// entry.argument(0)?.into(), -// 1, -// Vec::new(), -// ), -// PopInfo::Multi(ConcreteMultiPopLibfunc { -// popped_ty, -// signature, -// }) => { -// let range_check = super::increment_builtin_counter( -// context, -// entry, -// location, -// entry.argument(0)?.into(), -// )?; - -// let CoreTypeConcrete::Snapshot(InfoAndTypeConcreteType { ty, .. }) = -// registry.get_type(&signature.param_signatures[1].ty)? -// else { -// return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); -// }; - -// let CoreTypeConcrete::Array(InfoAndTypeConcreteType { ty, .. }) = -// registry.get_type(ty)? -// else { -// return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); -// }; - -// let CoreTypeConcrete::Struct(info) = registry.get_type(popped_ty)? else { -// return Err(Error::SierraAssert(SierraAssertError::BadTypeInfo)); -// }; -// debug_assert!(info.members.iter().all(|member_ty| member_ty == ty)); - -// ( -// &signature.param_signatures[1].ty, -// ty, -// entry.argument(1)?.into(), -// info.members.len(), -// vec![range_check], -// ) -// } -// }; - -// registry.build_type(context, helper, metadata, self_ty)?; -// let extract_len_value = entry.const_int_from_type(context, location, extract_len, len_ty)?; - -// let (elem_type, elem_layout) = -// registry.build_type_with_layout(context, helper, metadata, elem_ty)?; - -// let array_start = entry.extract_value(context, location, array_value, len_ty, 1)?; -// let array_end = entry.extract_value(context, location, array_value, len_ty, 2)?; - -// let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; -// let has_enough_data = entry.append_op_result(arith::cmpi( -// context, -// CmpiPredicate::Ule, -// extract_len_value, -// array_len, -// location, -// ))?; - -// let valid_block = helper.append_block(Block::new(&[])); -// let error_block = helper.append_block(Block::new(&[])); -// entry.append_operation(cf::cond_br( -// context, -// has_enough_data, -// valid_block, -// error_block, -// &[], -// &[], -// location, -// )); - -// { -// // Clone branch_values so that it doesn't interfere with the other branch. -// let mut branch_values = branch_values.clone(); - -// let value_size = valid_block.const_int( -// context, -// location, -// elem_layout.pad_to_align().size() * extract_len, -// 64, -// )?; - -// let value_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; -// let value_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( -// context, value_ptr, value_size, location, -// )?)?; - -// let array_ptr_ptr = valid_block.extract_value(context, location, array_value, ptr_ty, 0)?; -// let is_shared = is_shared(context, valid_block, location, array_ptr_ptr, elem_layout)?; - -// let array_ptr = valid_block.load(context, location, array_ptr_ptr, ptr_ty)?; -// let data_ptr = { -// let offset_elems = if REVERSE { -// valid_block.append_op_result(arith::subi(array_end, extract_len_value, location))? -// } else { -// array_start -// }; - -// let offset = valid_block.append_op_result(arith::extui( -// offset_elems, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let elem_stride = -// valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; -// let offset = -// valid_block.append_op_result(arith::muli(offset, elem_stride, location))?; - -// valid_block.gep( -// context, -// location, -// array_ptr, -// &[GepIndex::Value(offset)], -// IntegerType::new(context, 8).into(), -// )? -// }; - -// let array_value = -// valid_block.insert_value(context, location, array_value, new_array_ptr, 0)?; - -// let has_realloc = valid_block.append_op_result( -// ods::llvm::icmp( -// context, -// IntegerType::new(context, 1).into(), -// array_ptr, -// new_array_ptr, -// IntegerAttribute::new(IntegerType::new(context, 64).into(), 1).into(), -// location, -// ) -// .into(), -// )?; -// let array_value = valid_block.append_op_result(scf::r#if( -// has_realloc, -// &[array_value.r#type()], -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[])); - -// let k0 = block.const_int_from_type(context, location, 0, len_ty)?; -// let array_len = -// block.append_op_result(arith::subi(array_len, extract_len_value, location))?; - -// let array_value = block.insert_value(context, location, array_value, k0, 1)?; -// let array_value = -// block.insert_value(context, location, array_value, array_len, 2)?; -// let array_value = -// block.insert_value(context, location, array_value, array_len, 3)?; - -// block.append_operation(scf::r#yield(&[array_value], location)); -// region -// }, -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[])); - -// let array_value = if REVERSE { -// let array_end = block.append_op_result(arith::subi( -// array_end, -// extract_len_value, -// location, -// ))?; -// block.insert_value(context, location, array_value, array_end, 2)? -// } else { -// let array_start = block.append_op_result(arith::addi( -// array_start, -// extract_len_value, -// location, -// ))?; -// block.insert_value(context, location, array_value, array_start, 1)? -// }; - -// block.append_operation(scf::r#yield(&[array_value], location)); -// region -// }, -// location, -// ))?; - -// branch_values.push(array_value); -// branch_values.push(value_ptr); - -// valid_block.append_operation(helper.br(0, &branch_values, location)); -// } - -// { -// if CONSUME { -// let self_ty = match info { -// PopInfo::Single(info) => &info.signature.param_signatures[0].ty, -// PopInfo::Multi(info) => &info.signature.param_signatures[1].ty, -// }; - -// metadata -// .get::() -// .unwrap() -// .invoke_override(context, error_block, location, self_ty, array_value)?; -// } else { -// branch_values.push(array_value); -// } - -// error_block.append_operation(helper.br(1, &branch_values, location)); -// } - -// Ok(()) -// } - /// Generate MLIR operations for the `array_get` libfunc. pub fn build_get<'ctx, 'this>( context: &'ctx Context, @@ -1239,161 +1000,64 @@ pub fn build_get<'ctx, 'this>( let elem_stride = valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; - let value_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; - let value_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( - context, - value_ptr, - elem_stride, - location, - )?)?; - - let array_ptr = - valid_block.extract_value(context, location, entry.argument(1)?.into(), ptr_ty, 0)?; - let is_shared = is_shared(context, valid_block, location, array_ptr, elem_layout)?; - - let offset = valid_block.append_op_result(arith::addi( - array_start, - entry.argument(2)?.into(), - location, - ))?; - let offset = valid_block.append_op_result(arith::extui( - offset, + // Compute data pointer. + let source_offset = valid_block.addi(array_start, entry.argument(2)?.into(), location)?; + let source_offset = valid_block.extui( + source_offset, IntegerType::new(context, 64).into(), location, - ))?; - let offset = valid_block.append_op_result(arith::muli(offset, elem_stride, location))?; - + )?; + let source_offset = valid_block.muli(source_offset, elem_stride, location)?; + let source_ptr = + valid_block.extract_value(context, location, entry.argument(1)?.into(), ptr_ty, 0)?; + let source_ptr = valid_block.load(context, location, source_ptr, ptr_ty)?; let source_ptr = valid_block.gep( context, location, - array_ptr, - &[GepIndex::Value(offset)], + source_ptr, + &[GepIndex::Value(source_offset)], IntegerType::new(context, 8).into(), )?; - valid_block.append_operation(scf::r#if( - is_shared, - &[], - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - match metadata.get::() { - Some(dup_overrides_meta) if dup_overrides_meta.is_overriden(&info.ty) => { - let value = block.load(context, location, source_ptr, elem_ty)?; - let values = dup_overrides_meta - .invoke_override(context, &block, location, &info.ty, value)?; - block.store(context, location, source_ptr, values.0)?; - block.store(context, location, value_ptr, values.1)?; - } - _ => block.memcpy(context, location, source_ptr, value_ptr, elem_stride), - } - - metadata - .get::() - .unwrap() - .invoke_override( - context, - &block, - location, - &info.signature.param_signatures[1].ty, - entry.argument(1)?.into(), - )?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[])); - - block.memcpy(context, location, source_ptr, value_ptr, elem_stride); - - match metadata.get::() { - Some(drop_overrides_meta) if drop_overrides_meta.is_overriden(&info.ty) => { - let drop_loop = |o0, o1| { - block.append_operation(scf::r#for( - o0, - o1, - elem_stride, - { - let region = Region::new(); - let block = region.append_block(Block::new(&[( - IntegerType::new(context, 64).into(), - location, - )])); - - let value_ptr = block.gep( - context, - location, - array_ptr, - &[GepIndex::Value(block.argument(0)?.into())], - IntegerType::new(context, 8).into(), - )?; - let value = - block.load(context, location, value_ptr, elem_ty)?; - drop_overrides_meta.invoke_override( - context, &block, location, &info.ty, value, - )?; - - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); - - Result::Ok(()) - }; - - let o0 = block.append_op_result(arith::extui( - array_start, - IntegerType::new(context, 64).into(), - location, - ))?; - let o1 = block.append_op_result(arith::addi( - array_start, - entry.argument(2)?.into(), - location, - ))?; - let o1 = block.append_op_result(arith::extui( - o1, - IntegerType::new(context, 64).into(), - location, - ))?; - let o0 = block.append_op_result(arith::muli(o0, elem_stride, location))?; - let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; - drop_loop(o0, o1)?; - - let o0 = block.append_op_result(arith::addi(o1, elem_stride, location))?; - let o1 = block.append_op_result(arith::extui( - array_end, - IntegerType::new(context, 64).into(), - location, - ))?; - let o1 = block.append_op_result(arith::muli(o1, elem_stride, location))?; - drop_loop(o0, o1)?; - } - _ => {} - } + // Allocate output pointer. + let target_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; + let target_ptr = valid_block.append_op_result(ReallocBindingsMeta::realloc( + context, + target_ptr, + elem_stride, + location, + )?)?; - let array_ptr = block.gep( + // Clone the output data. + match metadata.get::() { + Some(dup_overrides_meta) if dup_overrides_meta.is_overriden(&info.ty) => { + let value = valid_block.load(context, location, source_ptr, elem_ty)?; + let values = dup_overrides_meta.invoke_override( context, + valid_block, location, - array_ptr, - &[GepIndex::Const( - -(calc_data_prefix_offset(elem_layout) as i32), - )], - IntegerType::new(context, 8).into(), + &info.ty, + value, )?; - block.append_operation(ReallocBindingsMeta::free(context, array_ptr, location)?); + valid_block.store(context, location, source_ptr, values.0)?; + valid_block.store(context, location, target_ptr, values.1)?; + } + _ => valid_block.memcpy(context, location, source_ptr, target_ptr, elem_stride), + } - block.append_operation(scf::r#yield(&[], location)); - region - }, - location, - )); + // Drop the input array. + metadata + .get::() + .unwrap() + .invoke_override( + context, + valid_block, + location, + &info.signature.param_signatures[1].ty, + entry.argument(1)?.into(), + )?; - valid_block.append_operation(helper.br(0, &[range_check, value_ptr], location)); + valid_block.append_operation(helper.br(0, &[range_check, target_ptr], location)); } { @@ -1414,371 +1078,6 @@ pub fn build_get<'ctx, 'this>( Ok(()) } -// /// Generate MLIR operations for the `array_slice` libfunc. -// pub fn build_slice<'ctx, 'this>( -// context: &'ctx Context, -// registry: &ProgramRegistry, -// entry: &'this Block<'ctx>, -// location: Location<'ctx>, -// helper: &LibfuncHelper<'ctx, 'this>, -// metadata: &mut MetadataStorage, -// info: &SignatureAndTypeConcreteLibfunc, -// ) -> Result<()> { -// // Signature: -// // Params: RangeCheck, Snapshot>, u32, u32 -// // Branches: -// // 0: RangeCheck, Snapshot> -// // 1: RangeCheck - -// let ptr_ty = llvm::r#type::pointer(context, 0); -// let len_ty = IntegerType::new(context, 32).into(); - -// let self_ty = registry.build_type( -// context, -// helper, -// metadata, -// &info.signature.param_signatures[1].ty, -// )?; - -// let range_check = -// super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; - -// let k0 = entry.const_int_from_type(context, location, 0, len_ty)?; -// let k1 = entry.const_int_from_type(context, location, 1, len_ty)?; - -// let array_start = -// entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 1)?; -// let array_end = entry.extract_value(context, location, entry.argument(1)?.into(), len_ty, 2)?; -// let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; - -// let slice_start = entry.argument(2)?.into(); -// let slice_len = entry.argument(3)?.into(); -// let slice_end = entry.append_op_result(arith::addi(slice_start, slice_len, location))?; - -// let slice_lhs_bound = entry.append_op_result(arith::cmpi( -// context, -// CmpiPredicate::Ule, -// slice_start, -// array_len, -// location, -// ))?; -// let slice_rhs_bound = entry.append_op_result(arith::cmpi( -// context, -// CmpiPredicate::Ule, -// slice_end, -// array_len, -// location, -// ))?; -// let slice_bounds = -// entry.append_op_result(arith::andi(slice_lhs_bound, slice_rhs_bound, location))?; - -// let valid_block = helper.append_block(Block::new(&[])); -// let error_block = helper.append_block(Block::new(&[])); -// entry.append_operation(cf::cond_br( -// context, -// slice_bounds, -// valid_block, -// error_block, -// &[], -// &[], -// location, -// )); - -// { -// let (elem_ty, elem_layout) = -// registry.build_type_with_layout(context, helper, metadata, &info.ty)?; -// let elem_stride = -// valid_block.const_int(context, location, elem_layout.pad_to_align().size(), 64)?; - -// let slice_size = valid_block.append_op_result(arith::extui( -// slice_len, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let slice_size = -// valid_block.append_op_result(arith::muli(elem_stride, slice_size, location))?; -// let slice_size_with_offset = valid_block.append_op_result(arith::addi( -// slice_size, -// valid_block.const_int(context, location, calc_data_prefix_offset(elem_layout), 64)?, -// location, -// ))?; - -// let array_ptr = -// valid_block.extract_value(context, location, entry.argument(1)?.into(), ptr_ty, 0)?; -// let null_ptr = valid_block.append_op_result(llvm::zero(ptr_ty, location))?; -// let is_null_source = valid_block.append_op_result( -// ods::llvm::icmp( -// context, -// IntegerType::new(context, 1).into(), -// array_ptr, -// null_ptr, -// IntegerAttribute::new(IntegerType::new(context, 64).into(), 0).into(), -// location, -// ) -// .into(), -// )?; -// let slice_ptr = valid_block.append_op_result(scf::r#if( -// is_null_source, -// &[ptr_ty], -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[])); - -// block.append_operation(scf::r#yield(&[null_ptr], location)); -// region -// }, -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[])); - -// let slice_ptr = block.append_op_result(llvm::zero(ptr_ty, location))?; -// let slice_ptr = block.append_op_result(ReallocBindingsMeta::realloc( -// context, -// slice_ptr, -// slice_size_with_offset, -// location, -// )?)?; -// block.store(context, location, slice_ptr, k1)?; - -// let slice_ptr = block.gep( -// context, -// location, -// slice_ptr, -// &[GepIndex::Const(calc_data_prefix_offset(elem_layout) as i32)], -// IntegerType::new(context, 8).into(), -// )?; - -// let is_shared = is_shared(context, &block, location, array_ptr, elem_layout)?; - -// let offset = -// block.append_op_result(arith::addi(array_start, slice_start, location))?; -// let offset = block.append_op_result(arith::extui( -// offset, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let offset = block.append_op_result(arith::muli(offset, elem_stride, location))?; - -// let source_ptr = block.gep( -// context, -// location, -// array_ptr, -// &[GepIndex::Value(offset)], -// IntegerType::new(context, 8).into(), -// )?; - -// block.append_operation(scf::r#if( -// is_shared, -// &[], -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[])); - -// match metadata.get::() { -// Some(dup_overrides_meta) -// if dup_overrides_meta.is_overriden(&info.ty) => -// { -// let k0 = block.const_int(context, location, 0, 64)?; -// block.append_operation(scf::r#for( -// k0, -// slice_size, -// elem_stride, -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[( -// IntegerType::new(context, 64).into(), -// location, -// )])); - -// let offset = block.argument(0)?.into(); -// let source_ptr = block.gep( -// context, -// location, -// source_ptr, -// &[GepIndex::Value(offset)], -// IntegerType::new(context, 8).into(), -// )?; -// let target_ptr = block.gep( -// context, -// location, -// slice_ptr, -// &[GepIndex::Value(offset)], -// IntegerType::new(context, 8).into(), -// )?; - -// let value = -// block.load(context, location, source_ptr, elem_ty)?; -// let values = dup_overrides_meta.invoke_override( -// context, &block, location, &info.ty, value, -// )?; -// block.store(context, location, source_ptr, values.0)?; -// block.store(context, location, target_ptr, values.1)?; - -// block.append_operation(scf::r#yield(&[], location)); -// region -// }, -// location, -// )); -// } -// _ => block.memcpy(context, location, source_ptr, slice_ptr, slice_size), -// } - -// metadata -// .get::() -// .unwrap() -// .invoke_override( -// context, -// &block, -// location, -// &info.signature.param_signatures[1].ty, -// entry.argument(1)?.into(), -// )?; - -// block.append_operation(scf::r#yield(&[], location)); -// region -// }, -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[])); - -// block.memcpy(context, location, source_ptr, slice_ptr, slice_size); - -// match metadata.get::() { -// Some(drop_overrides_meta) -// if drop_overrides_meta.is_overriden(&info.ty) => -// { -// let drop_loop = |o0, o1| { -// block.append_operation(scf::r#for( -// o0, -// o1, -// elem_stride, -// { -// let region = Region::new(); -// let block = region.append_block(Block::new(&[( -// IntegerType::new(context, 64).into(), -// location, -// )])); - -// let value_ptr = block.gep( -// context, -// location, -// array_ptr, -// &[GepIndex::Value(block.argument(0)?.into())], -// IntegerType::new(context, 8).into(), -// )?; -// let value = block -// .load(context, location, value_ptr, elem_ty)?; -// drop_overrides_meta.invoke_override( -// context, &block, location, &info.ty, value, -// )?; - -// block.append_operation(scf::r#yield(&[], location)); -// region -// }, -// location, -// )); - -// Result::Ok(()) -// }; - -// let o0 = block.append_op_result(arith::extui( -// array_start, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let o1 = block.append_op_result(arith::addi( -// array_start, -// slice_start, -// location, -// ))?; -// let o1 = block.append_op_result(arith::extui( -// o1, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let o0 = block.append_op_result(arith::muli( -// o0, -// elem_stride, -// location, -// ))?; -// let o1 = block.append_op_result(arith::muli( -// o1, -// elem_stride, -// location, -// ))?; -// drop_loop(o0, o1)?; - -// let o0 = block -// .append_op_result(arith::addi(o1, slice_size, location))?; -// let o1 = block.append_op_result(arith::extui( -// array_end, -// IntegerType::new(context, 64).into(), -// location, -// ))?; -// let o1 = block.append_op_result(arith::muli( -// o1, -// elem_stride, -// location, -// ))?; -// drop_loop(o0, o1)?; -// } -// _ => {} -// } - -// let array_ptr = block.gep( -// context, -// location, -// array_ptr, -// &[GepIndex::Const( -// -(calc_data_prefix_offset(elem_layout) as i32), -// )], -// IntegerType::new(context, 8).into(), -// )?; -// block.append_operation(ReallocBindingsMeta::free( -// context, array_ptr, location, -// )?); - -// block.append_operation(scf::r#yield(&[], location)); -// region -// }, -// location, -// )); - -// block.append_operation(scf::r#yield(&[slice_ptr], location)); -// region -// }, -// location, -// ))?; - -// let slice_value = valid_block.append_op_result(llvm::undef(self_ty, location))?; -// let slice_value = valid_block.insert_values( -// context, -// location, -// slice_value, -// &[slice_ptr, k0, slice_len, slice_len], -// )?; - -// valid_block.append_operation(helper.br(0, &[range_check, slice_value], location)); -// } - -// { -// metadata -// .get::() -// .ok_or(Error::MissingMetadata)? -// .invoke_override( -// context, -// error_block, -// location, -// &info.signature.param_signatures[1].ty, -// entry.argument(1)?.into(), -// )?; - -// error_block.append_operation(helper.br(1, &[range_check], location)); -// } - -// Ok(()) -// } - /// Generate MLIR operations for the `array_len` libfunc. pub fn build_len<'ctx, 'this>( context: &'ctx Context, @@ -2963,4 +2262,38 @@ mod test { ), ); } + + #[test] + fn asdf() { + let program = load_cairo! { + use array::ArrayTrait; + + fn run_test() -> (u32, u32, u32, u32) { + let mut numbers = ArrayTrait::new(); + numbers.append(4_u32); + numbers.append(3_u32); + numbers.append(2_u32); + numbers.append(1_u32); + ( + *numbers.at(0), + *numbers.at(1), + *numbers.at(2), + *numbers.at(3), + ) + } + }; + + let result = run_program(&program, "run_test", &[]); + assert_eq!( + result.return_value, + Value::Enum { + tag: 0, + value: Box::new(Value::Struct { + fields: vec![Value::Uint32(3)], + debug_name: None, + }), + debug_name: None, + }, + ); + } } diff --git a/src/values.rs b/src/values.rs index 737ed274c..577897b47 100644 --- a/src/values.rs +++ b/src/values.rs @@ -647,12 +647,13 @@ impl Value { // TODO: Drop suffix elements. let mut array_value = Vec::with_capacity(num_elems); - for i in 0..num_elems { + for i in start_offset_value..end_offset_value { // safe to create a NonNull because if the array has elements, the init_data_ptr can't be null. - let cur_elem_ptr = NonNull::new(array_ptr.byte_add(elem_stride * i)) - .to_native_assert_error( - "tried to make a non-null ptr out of a null one", - )?; + let cur_elem_ptr = + NonNull::new(array_ptr.byte_add(elem_stride * i as usize)) + .to_native_assert_error( + "tried to make a non-null ptr out of a null one", + )?; array_value.push(Self::from_ptr( cur_elem_ptr, &info.ty, From b05dbaed4565a89aad903d29a0330e9a4f0e0c73 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 14 Feb 2025 15:47:06 +0100 Subject: [PATCH 05/14] Implement `array_slice`. --- src/libfuncs/array.rs | 118 +++++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 36 deletions(-) diff --git a/src/libfuncs/array.rs b/src/libfuncs/array.rs index 46a383be9..668e309fb 100644 --- a/src/libfuncs/array.rs +++ b/src/libfuncs/array.rs @@ -76,8 +76,7 @@ pub fn build<'ctx, 'this>( build_get(context, registry, entry, location, helper, metadata, info) } ArrayConcreteLibfunc::Slice(info) => { - // build_slice(context, registry, entry, location, helper, metadata, info) - todo!() + build_slice(context, registry, entry, location, helper, metadata, info) } ArrayConcreteLibfunc::Len(info) => { build_len(context, registry, entry, location, helper, metadata, info) @@ -1078,6 +1077,87 @@ pub fn build_get<'ctx, 'this>( Ok(()) } +/// Generate MLIR operations for the `array_len` libfunc. +pub fn build_slice<'ctx, 'this>( + context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureAndTypeConcreteLibfunc, +) -> Result<()> { + let len_ty = IntegerType::new(context, 32).into(); + + let range_check = + super::increment_builtin_counter(context, entry, location, entry.argument(0)?.into())?; + + let array_obj = entry.argument(1)?.into(); + let array_start = entry.extract_value(context, location, array_obj, len_ty, 1)?; + let array_end = entry.extract_value(context, location, array_obj, len_ty, 2)?; + let array_len = entry.append_op_result(arith::subi(array_end, array_start, location))?; + + let slice_start = entry.argument(2)?.into(); + let slice_len = entry.argument(3)?.into(); + let slice_end = entry.append_op_result(arith::addi(slice_start, slice_len, location))?; + + let slice_lhs_bound = entry.append_op_result(arith::cmpi( + context, + CmpiPredicate::Ule, + slice_start, + array_len, + location, + ))?; + let slice_rhs_bound = entry.append_op_result(arith::cmpi( + context, + CmpiPredicate::Ule, + slice_end, + array_len, + location, + ))?; + let slice_bounds = + entry.append_op_result(arith::andi(slice_lhs_bound, slice_rhs_bound, location))?; + + let valid_block = helper.append_block(Block::new(&[])); + let error_block = helper.append_block(Block::new(&[])); + entry.append_operation(cf::cond_br( + context, + slice_bounds, + valid_block, + error_block, + &[], + &[], + location, + )); + + { + let array_start = valid_block.addi(array_start, slice_start, location)?; + let array_end = valid_block.addi(array_start, slice_len, location)?; + + let array_obj = valid_block.insert_value(context, location, array_obj, array_start, 1)?; + let array_obj = valid_block.insert_value(context, location, array_obj, array_end, 2)?; + + valid_block.append_operation(helper.br(0, &[range_check, array_obj], location)); + } + + { + metadata + .get::() + .ok_or(Error::MissingMetadata)? + .invoke_override( + context, + error_block, + location, + &info.signature.param_signatures[1].ty, + array_obj, + )?; + + error_block.append_operation(helper.br(1, &[range_check], location)); + } + + Ok(()) +} + /// Generate MLIR operations for the `array_len` libfunc. pub fn build_len<'ctx, 'this>( context: &'ctx Context, @@ -2262,38 +2342,4 @@ mod test { ), ); } - - #[test] - fn asdf() { - let program = load_cairo! { - use array::ArrayTrait; - - fn run_test() -> (u32, u32, u32, u32) { - let mut numbers = ArrayTrait::new(); - numbers.append(4_u32); - numbers.append(3_u32); - numbers.append(2_u32); - numbers.append(1_u32); - ( - *numbers.at(0), - *numbers.at(1), - *numbers.at(2), - *numbers.at(3), - ) - } - }; - - let result = run_program(&program, "run_test", &[]); - assert_eq!( - result.return_value, - Value::Enum { - tag: 0, - value: Box::new(Value::Struct { - fields: vec![Value::Uint32(3)], - debug_name: None, - }), - debug_name: None, - }, - ); - } } From 0ff06e47134058134ae65aeac42433c48c7bd174 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 14 Feb 2025 16:31:13 +0100 Subject: [PATCH 06/14] Fix contract executor. --- src/executor/contract.rs | 128 +++++++++++++++++++-------------------- src/values.rs | 3 +- 2 files changed, 65 insertions(+), 66 deletions(-) diff --git a/src/executor/contract.rs b/src/executor/contract.rs index a470bf5c8..8c7795221 100644 --- a/src/executor/contract.rs +++ b/src/executor/contract.rs @@ -380,52 +380,55 @@ impl AotContractExecutor { } let felt_layout = get_integer_layout(252).pad_to_align(); - let refcount_offset = get_integer_layout(32) - .align_to(felt_layout.align()) - .unwrap() - .pad_to_align() - .size(); + let refcount_offset = crate::types::array::calc_data_prefix_offset(felt_layout); - let ptr = match args.len() { + let len_u32: u32 = args + .len() + .try_into() + .to_native_assert_error("number of arguments should fit into a u32")?; + let array_ptr = match args.len() { 0 => std::ptr::null_mut(), _ => unsafe { - let ptr: *mut () = + let array_ptr: *mut () = libc_malloc(felt_layout.size() * args.len() + refcount_offset).cast(); // Write reference count. - ptr.cast::().write(1); - ptr.byte_add(refcount_offset) + array_ptr.cast::<(u32, u32)>().write((1, len_u32)); + array_ptr.byte_add(refcount_offset) }, }; - let len: u32 = args - .len() - .try_into() - .to_native_assert_error("number of arguments should fit into a u32")?; - - ptr.to_bytes(&mut invoke_data, |_| unreachable!())?; - if cfg!(target_arch = "aarch64") { - 0u32.to_bytes(&mut invoke_data, |_| unreachable!())?; // start - len.to_bytes(&mut invoke_data, |_| unreachable!())?; // end - len.to_bytes(&mut invoke_data, |_| unreachable!())?; // cap - } else if cfg!(target_arch = "x86_64") { - (0u32 as u64).to_bytes(&mut invoke_data, |_| unreachable!())?; // start - (len as u64).to_bytes(&mut invoke_data, |_| unreachable!())?; // end - (len as u64).to_bytes(&mut invoke_data, |_| unreachable!())?; // cap - } else { - unreachable!("unsupported architecture"); - } for (idx, elem) in args.iter().enumerate() { let f = elem.to_bytes_le(); unsafe { std::ptr::copy_nonoverlapping( f.as_ptr().cast::(), - ptr.byte_add(idx * felt_layout.size()).cast::(), + array_ptr.byte_add(idx * felt_layout.size()).cast::(), felt_layout.size(), ) }; } + // Make double pointer. + let array_ptr_ptr = unsafe { + let array_ptr_ptr = libc_malloc(size_of::<*mut ()>()).cast::<*mut ()>(); + array_ptr_ptr.write(array_ptr); + array_ptr_ptr + }; + + array_ptr_ptr.to_bytes(&mut invoke_data, |_| unreachable!())?; + if cfg!(target_arch = "aarch64") { + 0u32.to_bytes(&mut invoke_data, |_| unreachable!())?; // start + len_u32.to_bytes(&mut invoke_data, |_| unreachable!())?; // end + len_u32.to_bytes(&mut invoke_data, |_| unreachable!())?; // cap + } else if cfg!(target_arch = "x86_64") { + (0u32 as u64).to_bytes(&mut invoke_data, |_| unreachable!())?; // start + (len_u32 as u64).to_bytes(&mut invoke_data, |_| unreachable!())?; // end + (len_u32 as u64).to_bytes(&mut invoke_data, |_| unreachable!())?; // cap + } else { + unreachable!("unsupported architecture"); + } + // Pad invoke data to the 16 byte boundary avoid segfaults. #[cfg(target_arch = "aarch64")] const REGISTER_BYTES: usize = 64; @@ -520,62 +523,57 @@ impl AotContractExecutor { let tag = *unsafe { enum_ptr.cast::().as_ref() } as usize; let tag = tag & 0x01; // Filter out bits that are not part of the enum's tag. - // layout of both enum variants, both are a array of felts + // Layout of both enum variants (both are arrays of felts). let value_layout = unsafe { Layout::from_size_align_unchecked(24, 8) }; let value_ptr = unsafe { enum_ptr .cast::() .add(tag_layout.extend(value_layout)?.1) + .cast::>() + .read() }; let value_ptr = &mut value_ptr.cast(); - let array_ptr: *mut u8 = unsafe { *read_value(value_ptr) }; - let start: u32 = unsafe { *read_value(value_ptr) }; - let end: u32 = unsafe { *read_value(value_ptr) }; - let _cap: u32 = unsafe { *read_value(value_ptr) }; - - let elem_stride = felt_layout.pad_to_align().size(); + let array_ptr_ptr = unsafe { *read_value::<*mut NonNull<()>>(value_ptr) }; + let array_start = unsafe { *read_value::(value_ptr) }; + let array_end = unsafe { *read_value::(value_ptr) }; + let _array_capacity = unsafe { *read_value::(value_ptr) }; - // this pointer can be null if the array has a size of 0. - let data_ptr = unsafe { array_ptr.byte_add(elem_stride * start as usize) }; + let mut array_value = Vec::with_capacity((array_end - array_start) as usize); + if !array_ptr_ptr.is_null() { + let array_ptr = unsafe { array_ptr_ptr.read() }; - assert!(end >= start); - let num_elems = (end - start) as usize; - let mut array_value = Vec::with_capacity(num_elems); + let elem_stride = felt_layout.pad_to_align().size(); + for i in array_start..array_end { + let cur_elem_ptr = unsafe { array_ptr.byte_add(elem_stride * i as usize) }; - for i in 0..num_elems { - // safe to create a NonNull because if the array has elements, the data_ptr can't be null. - let cur_elem_ptr = NonNull::new(unsafe { data_ptr.byte_add(elem_stride * i) }) - .to_native_assert_error("data_ptr should not be null")?; - let data = unsafe { cur_elem_ptr.cast::<[u8; 32]>().as_mut() }; - data[31] &= 0x0F; // Filter out first 4 bits (they're outside an i252). - let data = Felt::from_bytes_le_slice(data); + let mut data = unsafe { cur_elem_ptr.cast::<[u8; 32]>().read() }; + data[31] &= 0x0F; // Filter out first 4 bits (they're outside an i252). - array_value.push(data); - } + array_value.push(Felt::from_bytes_le(&data)); + } - if !array_ptr.is_null() { unsafe { - let ptr = array_ptr.byte_sub(refcount_offset); - assert_eq!(ptr.cast::().read(), 1); - - libc_free(ptr.cast()); + let array_ptr = array_ptr.byte_sub(refcount_offset); + assert_eq!(array_ptr.cast::().read(), 1); + libc_free(array_ptr.as_ptr().cast()); + libc_free(array_ptr_ptr.cast()); } } - let error_msg = if tag != 0 { - let bytes_err: Vec<_> = array_value - .iter() - .flat_map(|felt| felt.to_bytes_be().to_vec()) - // remove null chars - .filter(|b| *b != 0) - .collect(); - let str_error = decode_error_message(&bytes_err); - - Some(str_error) - } else { - None + let error_msg = match tag { + 0 => None, + _ => { + Some(decode_error_message( + &array_value + .iter() + .flat_map(|felt| felt.to_bytes_be().to_vec()) + // remove null chars + .filter(|b| *b != 0) + .collect::>(), + )) + } }; // Restore the original builtin costs pointer. diff --git a/src/values.rs b/src/values.rs index 577897b47..fd14d17d1 100644 --- a/src/values.rs +++ b/src/values.rs @@ -628,7 +628,8 @@ impl Value { (false, null_mut()) } else { let array_ptr = array_ptr_ptr.read(); - let ref_count = dbg!(array_ptr.byte_sub(refcount_offset)) + let ref_count = array_ptr + .byte_sub(refcount_offset) .cast::() .as_mut() .unwrap(); From 966bcd33f805241a93b3b9836f6724081818b116 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 14 Feb 2025 18:34:00 +0100 Subject: [PATCH 07/14] Fix other bugs. --- src/libfuncs/array.rs | 18 ++++++- src/types/array.rs | 49 +++++++------------- src/types/felt252_dict.rs | 3 +- src/values.rs | 98 ++++++++++++++++++++++++++------------- 4 files changed, 102 insertions(+), 66 deletions(-) diff --git a/src/libfuncs/array.rs b/src/libfuncs/array.rs index 668e309fb..ec65e3d3b 100644 --- a/src/libfuncs/array.rs +++ b/src/libfuncs/array.rs @@ -567,7 +567,7 @@ pub fn build_append<'ctx, 'this>( context, location, array_ptr, - &[GepIndex::Const(4)], + &[GepIndex::Const(size_of::() as i32)], IntegerType::new(context, 8).into(), )?; block.store(context, location, max_len_ptr, k0)?; @@ -685,6 +685,7 @@ pub fn build_append<'ctx, 'this>( let array_ptr_ptr = entry.extract_value(context, location, array_obj, ptr_ty, 0)?; let array_ptr = entry.load(context, location, array_ptr_ptr, ptr_ty)?; + // Insert the value. let target_offset = entry.extract_value(context, location, array_obj, len_ty, 2)?; let target_offset = entry.extui( target_offset, @@ -702,12 +703,25 @@ pub fn build_append<'ctx, 'this>( entry.store(context, location, target_ptr, entry.argument(1)?.into())?; - // TODO: Update max length. + // Update array. let k1 = entry.const_int_from_type(context, location, 1, len_ty)?; let array_end = entry.extract_value(context, location, array_obj, len_ty, 2)?; let array_end = entry.addi(array_end, k1, location)?; let array_obj = entry.insert_value(context, location, array_obj, array_end, 2)?; + // Update max length. + let max_len_ptr = entry.gep( + context, + location, + array_ptr, + &[GepIndex::Const( + -((crate::types::array::calc_data_prefix_offset(elem_layout) - size_of::()) + as i32), + )], + IntegerType::new(context, 8).into(), + )?; + entry.store(context, location, max_len_ptr, array_end)?; + entry.append_operation(helper.br(0, &[array_obj], location)); Ok(()) } diff --git a/src/types/array.rs b/src/types/array.rs index a63559113..58f9d9ccb 100644 --- a/src/types/array.rs +++ b/src/types/array.rs @@ -313,48 +313,35 @@ fn build_drop<'ctx>( match metadata.get::() { Some(drop_overrides_meta) if drop_overrides_meta.is_overriden(&info.ty) => { - let value_start = block.extract_value( + let k0 = block.const_int(context, location, 0, 64)?; + let elem_stride = + block.const_int(context, location, elem_stride, 64)?; + + let max_len_ptr = block.gep( context, location, - entry.argument(0)?.into(), - IntegerType::new(context, 32).into(), - 1, + array_ptr, + &[GepIndex::Const( + -((refcount_offset - size_of::()) as i32), + )], + IntegerType::new(context, 8).into(), )?; - let value_end = block.extract_value( + let max_len = block.load( context, location, - entry.argument(0)?.into(), + max_len_ptr, IntegerType::new(context, 32).into(), - 2, )?; - - let value_start = block.append_op_result(arith::extui( - value_start, - IntegerType::new(context, 64).into(), - location, - ))?; - let value_end = block.append_op_result(arith::extui( - value_end, + let max_len = block.extui( + max_len, IntegerType::new(context, 64).into(), location, - ))?; - - let elem_stride = - block.const_int(context, location, elem_stride, 64)?; - let offset_start = block.append_op_result(arith::muli( - value_start, - elem_stride, - location, - ))?; - let offset_end = block.append_op_result(arith::muli( - value_end, - elem_stride, - location, - ))?; + )?; + let offset_end = block.muli(max_len, elem_stride, location)?; - // for each element in the aray, invoke its drop implementation + // Drop each element in the array. block.append_operation(scf::r#for( - offset_start, + k0, offset_end, elem_stride, { diff --git a/src/types/felt252_dict.rs b/src/types/felt252_dict.rs index 6afd2ebce..b81afb232 100644 --- a/src/types/felt252_dict.rs +++ b/src/types/felt252_dict.rs @@ -202,7 +202,6 @@ mod test { @dict } - }; let program2 = load_cairo! { fn run_test() -> Felt252Dict>> { @@ -211,8 +210,8 @@ mod test { dict } - }; + let result1 = run_program(&program, "run_test", &[]).return_value; let result2 = run_program(&program2, "run_test", &[]).return_value; diff --git a/src/values.rs b/src/values.rs index fd14d17d1..76ba169b9 100644 --- a/src/values.rs +++ b/src/values.rs @@ -624,8 +624,8 @@ impl Value { let array_ptr_ptr = *ptr.cast::<*mut *mut ()>().as_ref(); let refcount_offset = crate::types::array::calc_data_prefix_offset(elem_layout); - let (should_drop, array_ptr) = if array_ptr_ptr.is_null() { - (false, null_mut()) + let array_value = if array_ptr_ptr.is_null() { + Vec::new() } else { let array_ptr = array_ptr_ptr.read(); let ref_count = array_ptr @@ -633,40 +633,76 @@ impl Value { .cast::() .as_mut() .unwrap(); - *ref_count -= 1; + if should_drop { + *ref_count -= 1; + } - (*ref_count == 0, array_ptr) - }; + native_assert!( + end_offset_value >= start_offset_value, + "can't have an array with negative length" + ); + let num_elems = (end_offset_value - start_offset_value) as usize; - native_assert!( - end_offset_value >= start_offset_value, - "can't have an array with negative length" - ); - let num_elems = (end_offset_value - start_offset_value) as usize; + // Drop prefix elements. + if should_drop { + for i in 0..start_offset_value { + let cur_elem_ptr = + NonNull::new(array_ptr.byte_add(elem_stride * i as usize)) + .to_native_assert_error( + "tried to make a non-null ptr out of a null one", + )?; + drop(Self::from_ptr( + cur_elem_ptr, + &info.ty, + registry, + should_drop, + )?); + } + } - // TODO: Drop prefix elements. - // TODO: Drop suffix elements. + let mut array_value = Vec::with_capacity(num_elems); + for i in start_offset_value..end_offset_value { + let cur_elem_ptr = + NonNull::new(array_ptr.byte_add(elem_stride * i as usize)) + .to_native_assert_error( + "tried to make a non-null ptr out of a null one", + )?; + array_value.push(Self::from_ptr( + cur_elem_ptr, + &info.ty, + registry, + *ref_count == 0, + )?); + } - let mut array_value = Vec::with_capacity(num_elems); - for i in start_offset_value..end_offset_value { - // safe to create a NonNull because if the array has elements, the init_data_ptr can't be null. - let cur_elem_ptr = - NonNull::new(array_ptr.byte_add(elem_stride * i as usize)) - .to_native_assert_error( - "tried to make a non-null ptr out of a null one", - )?; - array_value.push(Self::from_ptr( - cur_elem_ptr, - &info.ty, - registry, - should_drop, - )?); - } + // Drop suffix elements. + if should_drop { + let array_max_len = array_ptr + .byte_sub(refcount_offset - size_of::()) + .cast::() + .read(); + for i in end_offset_value..array_max_len { + let cur_elem_ptr = + NonNull::new(array_ptr.byte_add(elem_stride * i as usize)) + .to_native_assert_error( + "tried to make a non-null ptr out of a null one", + )?; + drop(Self::from_ptr( + cur_elem_ptr, + &info.ty, + registry, + should_drop, + )?); + } + } - if should_drop { - libc_free(array_ptr.byte_sub(refcount_offset).cast()); - libc_free(array_ptr_ptr.cast()); - } + if *ref_count == 0 { + libc_free(array_ptr.byte_sub(refcount_offset).cast()); + libc_free(array_ptr_ptr.cast()); + } + + array_value + }; Self::Array(array_value) } From 207ff9e2bc94823070fb1a50ba51e5e2d73afad0 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 14 Feb 2025 18:52:20 +0100 Subject: [PATCH 08/14] Fix AOT contract runner. --- src/executor/contract.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/executor/contract.rs b/src/executor/contract.rs index 8c7795221..015cafabd 100644 --- a/src/executor/contract.rs +++ b/src/executor/contract.rs @@ -523,26 +523,18 @@ impl AotContractExecutor { let tag = *unsafe { enum_ptr.cast::().as_ref() } as usize; let tag = tag & 0x01; // Filter out bits that are not part of the enum's tag. - // Layout of both enum variants (both are arrays of felts). let value_layout = unsafe { Layout::from_size_align_unchecked(24, 8) }; - let value_ptr = unsafe { - enum_ptr - .cast::() - .add(tag_layout.extend(value_layout)?.1) - .cast::>() - .read() - }; - - let value_ptr = &mut value_ptr.cast(); + let mut value_ptr = unsafe { enum_ptr.byte_add(tag_layout.extend(value_layout)?.1).cast() }; - let array_ptr_ptr = unsafe { *read_value::<*mut NonNull<()>>(value_ptr) }; - let array_start = unsafe { *read_value::(value_ptr) }; - let array_end = unsafe { *read_value::(value_ptr) }; - let _array_capacity = unsafe { *read_value::(value_ptr) }; + let array_ptr_ptr = unsafe { *read_value::<*mut NonNull<()>>(&mut value_ptr) }; + let array_start = unsafe { *read_value::(&mut value_ptr) }; + let array_end = unsafe { *read_value::(&mut value_ptr) }; + let _array_capacity = unsafe { *read_value::(&mut value_ptr) }; let mut array_value = Vec::with_capacity((array_end - array_start) as usize); if !array_ptr_ptr.is_null() { - let array_ptr = unsafe { array_ptr_ptr.read() }; + let array_ptr = unsafe { dbg!(array_ptr_ptr).read() }; + dbg!(array_ptr); let elem_stride = felt_layout.pad_to_align().size(); for i in array_start..array_end { From ac87223b71611ba5c8503f698856aa2cf66cf031 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 14 Feb 2025 19:00:51 +0100 Subject: [PATCH 09/14] Fix array from_ptr drops. --- src/values.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/values.rs b/src/values.rs index 76ba169b9..8e6806ad4 100644 --- a/src/values.rs +++ b/src/values.rs @@ -643,8 +643,8 @@ impl Value { ); let num_elems = (end_offset_value - start_offset_value) as usize; - // Drop prefix elements. - if should_drop { + if *ref_count == 0 { + // Drop prefix elements. for i in 0..start_offset_value { let cur_elem_ptr = NonNull::new(array_ptr.byte_add(elem_stride * i as usize)) @@ -675,8 +675,8 @@ impl Value { )?); } - // Drop suffix elements. - if should_drop { + if *ref_count == 0 { + // Drop suffix elements. let array_max_len = array_ptr .byte_sub(refcount_offset - size_of::()) .cast::() @@ -694,9 +694,8 @@ impl Value { should_drop, )?); } - } - if *ref_count == 0 { + // Free array storage. libc_free(array_ptr.byte_sub(refcount_offset).cast()); libc_free(array_ptr_ptr.cast()); } From 749f5c09d786a3878a43b3eba559bb22b960df35 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 14 Feb 2025 19:29:38 +0100 Subject: [PATCH 10/14] Fix starknet module. --- src/starknet.rs | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/starknet.rs b/src/starknet.rs index 8f0774ef6..9355a70c3 100644 --- a/src/starknet.rs +++ b/src/starknet.rs @@ -8,7 +8,7 @@ pub type SyscallResult = std::result::Result>; #[repr(C)] #[derive(Debug)] pub struct ArrayAbi { - pub ptr: *mut T, + pub ptr: *mut *mut T, pub since: u32, pub until: u32, pub capacity: u32, @@ -23,7 +23,7 @@ impl From<&ArrayAbi> for Vec { let len = until_offset - since_offset; match len { 0 => &[], - _ => std::slice::from_raw_parts(value.ptr.add(since_offset), len), + _ => std::slice::from_raw_parts(value.ptr.read().add(since_offset), len), } } .iter() @@ -540,11 +540,11 @@ impl StarknetSyscallHandler for DummySyscallHandler { // TODO: Move to the correct place or remove if unused. pub(crate) mod handler { use super::*; - use crate::utils::{get_integer_layout, libc_free, libc_malloc}; + use crate::utils::{libc_free, libc_malloc}; use std::{ alloc::Layout, fmt::Debug, - mem::{self, size_of, ManuallyDrop, MaybeUninit}, + mem::{size_of, ManuallyDrop, MaybeUninit}, ptr::{null_mut, NonNull}, }; @@ -908,11 +908,8 @@ pub(crate) mod handler { capacity: 0, }, _ => { - let refcount_offset = get_integer_layout(32) - .align_to(mem::align_of::()) - .unwrap() - .pad_to_align() - .size(); + let refcount_offset = + crate::types::array::calc_data_prefix_offset(Layout::new::()); let ptr = libc_malloc( Layout::array::(data.len()).unwrap().size() + refcount_offset, ) as *mut E; @@ -925,8 +922,11 @@ pub(crate) mod handler { ptr.add(i).write(val.clone()); } + let ptr_ptr = libc_malloc(size_of::<*mut ()>()).cast::<*mut E>(); + ptr_ptr.write(ptr); + ArrayAbi { - ptr, + ptr: ptr_ptr, since: 0, until: len, capacity: len, @@ -940,15 +940,14 @@ pub(crate) mod handler { return; } - let refcount_offset = get_integer_layout(32) - .align_to(mem::align_of::()) - .unwrap() - .pad_to_align() - .size(); + let refcount_offset = crate::types::array::calc_data_prefix_offset(Layout::new::()); - let ptr = data.ptr.byte_sub(refcount_offset); + let ptr = data.ptr.read().byte_sub(refcount_offset); match ptr.cast::().read() { - 1 => libc_free(ptr.cast()), + 1 => { + libc_free(ptr.cast()); + libc_free(data.ptr.cast()); + } n => ptr.cast::().write(n - 1), } } @@ -1157,7 +1156,6 @@ pub(crate) mod handler { let contract_address_salt = Felt::from(contract_address_salt); let calldata_vec: Vec<_> = calldata.into(); - unsafe { Self::drop_mlir_array(calldata); } @@ -1217,7 +1215,6 @@ pub(crate) mod handler { let function_selector = Felt::from(function_selector); let calldata_vec: Vec = calldata.into(); - unsafe { Self::drop_mlir_array(calldata); } @@ -1251,7 +1248,6 @@ pub(crate) mod handler { let entry_point_selector = Felt::from(entry_point_selector); let calldata_vec: Vec = calldata.into(); - unsafe { Self::drop_mlir_array(calldata); } @@ -1325,14 +1321,10 @@ pub(crate) mod handler { data: &ArrayAbi, ) { let keys_vec: Vec<_> = keys.into(); - - unsafe { - Self::drop_mlir_array(keys); - } - let data_vec: Vec<_> = data.into(); unsafe { + Self::drop_mlir_array(keys); Self::drop_mlir_array(data); } @@ -1389,7 +1381,7 @@ pub(crate) mod handler { let len = until_offset - since_offset; match len { 0 => &[], - _ => std::slice::from_raw_parts(input.ptr.add(since_offset), len), + _ => std::slice::from_raw_parts(input.ptr.read().add(since_offset), len), } }; From 14c3777ea2fbc0cc8290ff84e768c453f2ddcda7 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Tue, 18 Feb 2025 13:40:07 +0100 Subject: [PATCH 11/14] Fix stuff. --- Makefile | 2 +- src/executor/contract.rs | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index d47c05619..1bbdf0cf5 100644 --- a/Makefile +++ b/Makefile @@ -74,7 +74,7 @@ proptest: check-llvm needs-cairo2 .PHONY: test-cli test-ci: check-llvm needs-cairo2 build-alexandria - cargo test --profile ci --features=scarb,with-cheatcode,with-debug-utils + RUST_TEST_THREADS=1 cargo test --profile ci --features=scarb,with-cheatcode,with-debug-utils .PHONY: proptest-cli proptest-ci: check-llvm needs-cairo2 diff --git a/src/executor/contract.rs b/src/executor/contract.rs index 015cafabd..8c659c6de 100644 --- a/src/executor/contract.rs +++ b/src/executor/contract.rs @@ -73,7 +73,7 @@ use std::{ fs::{self, File}, io, path::{Path, PathBuf}, - ptr::NonNull, + ptr::{self, NonNull}, sync::Arc, }; use tempfile::NamedTempFile; @@ -410,10 +410,14 @@ impl AotContractExecutor { } // Make double pointer. - let array_ptr_ptr = unsafe { - let array_ptr_ptr = libc_malloc(size_of::<*mut ()>()).cast::<*mut ()>(); - array_ptr_ptr.write(array_ptr); - array_ptr_ptr + let array_ptr_ptr = if array_ptr.is_null() { + ptr::null_mut() + } else { + unsafe { + let array_ptr_ptr = libc_malloc(size_of::<*mut ()>()).cast::<*mut ()>(); + array_ptr_ptr.write(array_ptr); + array_ptr_ptr + } }; array_ptr_ptr.to_bytes(&mut invoke_data, |_| unreachable!())?; @@ -533,8 +537,7 @@ impl AotContractExecutor { let mut array_value = Vec::with_capacity((array_end - array_start) as usize); if !array_ptr_ptr.is_null() { - let array_ptr = unsafe { dbg!(array_ptr_ptr).read() }; - dbg!(array_ptr); + let array_ptr = unsafe { array_ptr_ptr.read() }; let elem_stride = felt_layout.pad_to_align().size(); for i in array_start..array_end { From e212ad8c53148618bee86cf072b7277695415ad4 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Tue, 18 Feb 2025 14:54:48 +0100 Subject: [PATCH 12/14] Fix bug. --- src/starknet.rs | 3 ++- tests/tests/starknet/syscalls.rs | 9 ++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/starknet.rs b/src/starknet.rs index 9355a70c3..d9ae13321 100644 --- a/src/starknet.rs +++ b/src/starknet.rs @@ -914,10 +914,11 @@ pub(crate) mod handler { Layout::array::(data.len()).unwrap().size() + refcount_offset, ) as *mut E; + let len: u32 = data.len().try_into().unwrap(); ptr.cast::().write(1); + ptr.byte_add(size_of::()).cast::().write(len); let ptr = ptr.byte_add(refcount_offset); - let len: u32 = data.len().try_into().unwrap(); for (i, val) in data.iter().enumerate() { ptr.add(i).write(val.clone()); } diff --git a/tests/tests/starknet/syscalls.rs b/tests/tests/starknet/syscalls.rs index 2a7d9bbad..86f91d972 100644 --- a/tests/tests/starknet/syscalls.rs +++ b/tests/tests/starknet/syscalls.rs @@ -1,8 +1,3 @@ -use std::{ - collections::{HashMap, VecDeque}, - sync::{Arc, Mutex}, -}; - use crate::common::{load_cairo_path, run_native_program}; use cairo_lang_runner::SierraCasmRunner; use cairo_lang_sierra::program::Program; @@ -16,6 +11,10 @@ use cairo_native::{ use lazy_static::lazy_static; use pretty_assertions_sorted::{assert_eq, assert_eq_sorted}; use starknet_types_core::felt::Felt; +use std::{ + collections::{HashMap, VecDeque}, + sync::{Arc, Mutex}, +}; type Log = (Vec, Vec); type L2ToL1Message = (Felt, Vec); From 5505c9cdeb1d92c12c68a52e5380c1ddc54ba5cf Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Tue, 18 Feb 2025 15:48:53 +0100 Subject: [PATCH 13/14] Restore makefile. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1bbdf0cf5..d47c05619 100644 --- a/Makefile +++ b/Makefile @@ -74,7 +74,7 @@ proptest: check-llvm needs-cairo2 .PHONY: test-cli test-ci: check-llvm needs-cairo2 build-alexandria - RUST_TEST_THREADS=1 cargo test --profile ci --features=scarb,with-cheatcode,with-debug-utils + cargo test --profile ci --features=scarb,with-cheatcode,with-debug-utils .PHONY: proptest-cli proptest-ci: check-llvm needs-cairo2 From ff67e7a638a2ecbb71461dacbea1b991af833bb3 Mon Sep 17 00:00:00 2001 From: Esteve Soler Arderiu Date: Fri, 21 Feb 2025 11:33:48 +0100 Subject: [PATCH 14/14] Fix libfunc name mistype. --- src/libfuncs/array.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libfuncs/array.rs b/src/libfuncs/array.rs index ec65e3d3b..60724afcf 100644 --- a/src/libfuncs/array.rs +++ b/src/libfuncs/array.rs @@ -1091,7 +1091,7 @@ pub fn build_get<'ctx, 'this>( Ok(()) } -/// Generate MLIR operations for the `array_len` libfunc. +/// Generate MLIR operations for the `array_slice` libfunc. pub fn build_slice<'ctx, 'this>( context: &'ctx Context, _registry: &ProgramRegistry,