Skip to content

Commit

Permalink
Add range_pop_front libfunc.
Browse files Browse the repository at this point in the history
commit-id:12946952
  • Loading branch information
liorgold2 committed Aug 26, 2024
1 parent b3bf2e0 commit a7707f6
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use cairo_lang_sierra::extensions::mem::MemConcreteLibfunc;
use cairo_lang_sierra::extensions::nullable::NullableConcreteLibfunc;
use cairo_lang_sierra::extensions::pedersen::PedersenConcreteLibfunc;
use cairo_lang_sierra::extensions::poseidon::PoseidonConcreteLibfunc;
use cairo_lang_sierra::extensions::range::RangeConcreteLibfunc;
use cairo_lang_sierra::extensions::starknet::testing::TestingConcreteLibfunc;
use cairo_lang_sierra::extensions::starknet::StarkNetConcreteLibfunc;
use cairo_lang_sierra::extensions::structure::StructConcreteLibfunc;
Expand Down Expand Up @@ -411,6 +412,9 @@ pub fn core_libfunc_ap_change<InfoProvider: InvocationApChangeInfoProvider>(
Circuit(CircuitConcreteLibfunc::U96SingleLimbLessThanGuaranteeVerify(_)) => {
vec![ApChange::Known(0)]
}
Range(libfunc) => match libfunc {
RangeConcreteLibfunc::PopFront(_) => vec![ApChange::Known(1), ApChange::Known(1)],
},
}
}

Expand Down
6 changes: 6 additions & 0 deletions crates/cairo-lang-sierra-gas/src/core_libfunc_cost_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use cairo_lang_sierra::extensions::mem::MemConcreteLibfunc::{
use cairo_lang_sierra::extensions::nullable::NullableConcreteLibfunc;
use cairo_lang_sierra::extensions::pedersen::PedersenConcreteLibfunc;
use cairo_lang_sierra::extensions::poseidon::PoseidonConcreteLibfunc;
use cairo_lang_sierra::extensions::range::RangeConcreteLibfunc;
use cairo_lang_sierra::extensions::structure::StructConcreteLibfunc;
use cairo_lang_sierra::ids::ConcreteTypeId;
use cairo_lang_sierra::program::Function;
Expand Down Expand Up @@ -581,6 +582,11 @@ pub fn core_libfunc_cost(
vec![ConstCost { steps: 32, holes: 0, range_checks: 0, range_checks96: 6 }.into()]
}
},
Range(libfunc) => match libfunc {
RangeConcreteLibfunc::PopFront(_) => {
vec![ConstCost::steps(2).into(), ConstCost::steps(3).into()]
}
},
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/cairo-lang-sierra-to-casm/src/invocations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ mod misc;
mod nullable;
mod pedersen;
mod poseidon;
mod range;
mod range_reduction;
mod starknet;
mod structure;
Expand Down Expand Up @@ -721,6 +722,7 @@ pub fn compile_invocation(
},
BoundedInt(libfunc) => int::bounded::build(libfunc, builder),
Circuit(libfunc) => circuit::build(libfunc, builder),
Range(libfunc) => range::build(libfunc, builder),
}
}

Expand Down
46 changes: 46 additions & 0 deletions crates/cairo-lang-sierra-to-casm/src/invocations/range.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use cairo_lang_casm::builder::CasmBuilder;
use cairo_lang_casm::casm_build_extend;
use cairo_lang_sierra::extensions::range::RangeConcreteLibfunc;

use super::{CompiledInvocation, CompiledInvocationBuilder, InvocationError};
use crate::invocations::{add_input_variables, get_non_fallthrough_statement_id};

/// Builds instructions for `Range` operations.
pub fn build(
libfunc: &RangeConcreteLibfunc,
builder: CompiledInvocationBuilder<'_>,
) -> Result<CompiledInvocation, InvocationError> {
match libfunc {
RangeConcreteLibfunc::PopFront(_) => build_pop_front(builder),
}
}

/// Libfunc for reducing `[a, b)` to `[a + 1, b)`.
fn build_pop_front(
builder: CompiledInvocationBuilder<'_>,
) -> Result<CompiledInvocation, InvocationError> {
let [start, end] = builder.try_get_refs::<1>()?[0].try_unpack()?;

let mut casm_builder = CasmBuilder::default();
add_input_variables! {casm_builder,
deref start;
deref end;
};
casm_build_extend! {casm_builder,
tempvar is_non_empty = end - start;
jump NonEmpty if is_non_empty != 0;
jump Failure;
NonEmpty:
const one = 1;
let new_start = start + one;
};
let failure_handle = get_non_fallthrough_statement_id(&builder);
Ok(builder.build_from_casm_builder(
casm_builder,
[
("Fallthrough", &[&[new_start, end], &[start]], None),
("Failure", &[], Some(failure_handle)),
],
Default::default(),
))
}
3 changes: 2 additions & 1 deletion crates/cairo-lang-sierra/src/extensions/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use super::modules::unconditional_jump::UnconditionalJumpLibfunc;
use super::nullable::{NullableLibfunc, NullableType};
use super::pedersen::{PedersenLibfunc, PedersenType};
use super::poseidon::{PoseidonLibfunc, PoseidonType};
use super::range::RangeType;
use super::range::{RangeLibfunc, RangeType};
use super::range_check::{RangeCheck96Type, RangeCheckType};
use super::segment_arena::SegmentArenaType;
use super::snapshot::{SnapshotTakeLibfunc, SnapshotType};
Expand Down Expand Up @@ -139,6 +139,7 @@ define_libfunc_hierarchy! {
Felt252DictEntry(Felt252DictEntryLibfunc),
Pedersen(PedersenLibfunc),
Poseidon(PoseidonLibfunc),
Range(RangeLibfunc),
StarkNet(StarkNetLibfunc),
Debug(DebugLibfunc),
SnapshotTake(SnapshotTakeLibfunc),
Expand Down
60 changes: 59 additions & 1 deletion crates/cairo-lang-sierra/src/extensions/modules/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ use super::int::signed::{Sint16Type, Sint32Type, Sint64Type, Sint8Type};
use super::int::signed128::Sint128Type;
use super::int::unsigned::{Uint16Type, Uint32Type, Uint64Type, Uint8Type};
use super::int::unsigned128::Uint128Type;
use crate::define_libfunc_hierarchy;
use crate::extensions::lib_func::{
BranchSignature, DeferredOutputKind, LibfuncSignature, OutputVarInfo, ParamSignature,
SierraApChange, SignatureOnlyGenericLibfunc, SignatureSpecializationContext,
};
use crate::extensions::type_specialization_context::TypeSpecializationContext;
use crate::extensions::types::{
GenericTypeArgGenericType, GenericTypeArgGenericTypeWrapper, TypeInfo,
};
use crate::extensions::{NamedType, SpecializationError};
use crate::extensions::{
args_as_single_type, NamedType, OutputVarReferenceInfo, SpecializationError,
};
use crate::ids::GenericTypeId;
use crate::program::GenericArg;

Expand Down Expand Up @@ -62,3 +69,54 @@ impl GenericTypeArgGenericType for RangeTypeWrapped {
}
}
pub type RangeType = GenericTypeArgGenericTypeWrapper<RangeTypeWrapped>;

define_libfunc_hierarchy! {
pub enum RangeLibfunc {
PopFront(RangePopFrontLibfunc),
}, RangeConcreteLibfunc
}

/// Libfunc that takes the range `[x, y)` and if `x < y`, returns the range `[x + 1, y)` and the
/// value `x`.
#[derive(Default)]
pub struct RangePopFrontLibfunc {}
impl SignatureOnlyGenericLibfunc for RangePopFrontLibfunc {
const STR_ID: &'static str = "range_pop_front";

fn specialize_signature(
&self,
context: &dyn SignatureSpecializationContext,
args: &[GenericArg],
) -> Result<LibfuncSignature, SpecializationError> {
let ty = args_as_single_type(args)?;
let range_ty = context.get_wrapped_concrete_type(RangeType::id(), ty.clone())?;

Ok(LibfuncSignature {
param_signatures: vec![ParamSignature::new(range_ty.clone())],
branch_signatures: vec![
// Success.
BranchSignature {
vars: vec![
OutputVarInfo {
ty: range_ty,
ref_info: OutputVarReferenceInfo::Deferred(
DeferredOutputKind::AddConst { param_idx: 0 },
),
},
OutputVarInfo {
ty,
ref_info: OutputVarReferenceInfo::PartialParam { param_idx: 0 },
},
],
ap_change: SierraApChange::Known { new_vars_only: false },
},
// Failure.
BranchSignature {
vars: vec![],
ap_change: SierraApChange::Known { new_vars_only: false },
},
],
fallthrough: Some(0),
})
}
}
1 change: 1 addition & 0 deletions crates/cairo-lang-sierra/src/simulation/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ pub fn simulate<
CoreConcreteLibfunc::Coupon(_) => unimplemented!(),
CoreConcreteLibfunc::BoundedInt(_) => unimplemented!(),
CoreConcreteLibfunc::Circuit(_) => unimplemented!(),
CoreConcreteLibfunc::Range(_) => unimplemented!(),
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
"nullable_forward_snapshot",
"nullable_from_box",
"pedersen",
"range_pop_front",
"redeposit_gas",
"rename",
"replace_class_syscall",
Expand Down
1 change: 1 addition & 0 deletions tests/e2e_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ cairo_lang_test_utils::test_file_test_with_runner!(
i8: "i8",
nullable: "nullable",
poseidon: "poseidon",
range: "range",
snapshot: "snapshot",
u128: "u128",
u16: "u16",
Expand Down
60 changes: 60 additions & 0 deletions tests/e2e_test_data/libfuncs/range
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//! > range_pop_front libfunc

//! > test_runner_name
SmallE2ETestRunner

//! > cairo
// TODO(lior): Move to `range.cairo`.
extern type Range<T>;
extern fn range_pop_front<T>(range: Range<T>) -> Option<(Range<T>, T)> nopanic;

fn foo(v: Range<i16>) -> Option<(Range<i16>, i16)> {
range_pop_front(v)
}

//! > casm
[fp + -3] = [ap + 0] + [fp + -4], ap++;
jmp rel 4 if [ap + -1] != 0;
jmp rel 9;
[ap + 0] = 0, ap++;
[ap + 0] = [fp + -4] + 1, ap++;
[ap + 0] = [fp + -3], ap++;
[ap + 0] = [fp + -4], ap++;
ret;
[ap + 0] = 1, ap++;
[ap + 0] = 0, ap++;
[ap + 0] = 0, ap++;
[ap + 0] = 0, ap++;
ret;

//! > function_costs
test::foo: OrderedHashMap({Const: 700})

//! > sierra_code
type Range<i16> = Range<i16> [storable: true, drop: true, dup: true, zero_sized: false];
type Unit = Struct<ut@Tuple> [storable: true, drop: true, dup: true, zero_sized: true];
type i16 = i16 [storable: true, drop: true, dup: true, zero_sized: false];
type Tuple<Range<i16>, i16> = Struct<ut@Tuple, Range<i16>, i16> [storable: true, drop: true, dup: true, zero_sized: false];
type core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)> = Enum<ut@core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>, Tuple<Range<i16>, i16>, Unit> [storable: true, drop: true, dup: true, zero_sized: false];

libfunc range_pop_front<i16> = range_pop_front<i16>;
libfunc branch_align = branch_align;
libfunc struct_construct<Tuple<Range<i16>, i16>> = struct_construct<Tuple<Range<i16>, i16>>;
libfunc enum_init<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>, 0> = enum_init<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>, 0>;
libfunc store_temp<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>> = store_temp<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>>;
libfunc struct_construct<Unit> = struct_construct<Unit>;
libfunc enum_init<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>, 1> = enum_init<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>, 1>;

range_pop_front<i16>([0]) { fallthrough([1], [2]) 6() }; // 0
branch_align() -> (); // 1
struct_construct<Tuple<Range<i16>, i16>>([1], [2]) -> ([3]); // 2
enum_init<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>, 0>([3]) -> ([4]); // 3
store_temp<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>>([4]) -> ([4]); // 4
return([4]); // 5
branch_align() -> (); // 6
struct_construct<Unit>() -> ([5]); // 7
enum_init<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>, 1>([5]) -> ([6]); // 8
store_temp<core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>>([6]) -> ([6]); // 9
return([6]); // 10

test::foo@0([0]: Range<i16>) -> (core::option::Option::<(test::Range::<core::integer::i16>, core::integer::i16)>);

0 comments on commit a7707f6

Please sign in to comment.