Skip to content

Commit

Permalink
Add int_range_pop_front libfunc.
Browse files Browse the repository at this point in the history
commit-id:12946952
  • Loading branch information
liorgold2 committed Aug 27, 2024
1 parent b023a6f commit c392a11
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 3 deletions.
9 changes: 9 additions & 0 deletions corelib/src/internal.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,12 @@ pub extern fn require_implicit<Implicit>() implicits(Implicit) nopanic;
extern type index_enum_type<const NUM_VARIANTS: felt252>;

pub(crate) mod bounded_int;

/// Same as `Option`, except that the order of the variants is reversed.
/// This is used as the return type of some libfuncs for efficiency reasons.
#[must_use]
#[derive(Copy, Drop, Debug, PartialEq)]
pub enum OptionRev<T> {
None,
Some: T,
}
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::IntRangeConcreteLibfunc;
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)]
}
IntRange(libfunc) => match libfunc {
IntRangeConcreteLibfunc::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::IntRangeConcreteLibfunc;
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()]
}
},
IntRange(libfunc) => match libfunc {
IntRangeConcreteLibfunc::PopFront(_) => {
vec![ConstCost::steps(2).into(), ConstCost::steps(2).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),
IntRange(libfunc) => range::build(libfunc, builder),
}
}

Expand Down
44 changes: 44 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,44 @@
use cairo_lang_casm::builder::CasmBuilder;
use cairo_lang_casm::casm_build_extend;
use cairo_lang_sierra::extensions::range::IntRangeConcreteLibfunc;

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: &IntRangeConcreteLibfunc,
builder: CompiledInvocationBuilder<'_>,
) -> Result<CompiledInvocation, InvocationError> {
match libfunc {
IntRangeConcreteLibfunc::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,
const one = 1;
let new_start = start + one;
tempvar is_non_empty = end - start;
jump NonEmpty if is_non_empty != 0;
};
let non_empty_handle = get_non_fallthrough_statement_id(&builder);
Ok(builder.build_from_casm_builder(
casm_builder,
[
("Fallthrough", &[], None),
("NonEmpty", &[&[new_start, end], &[start]], Some(non_empty_handle)),
],
Default::default(),
))
}
5 changes: 3 additions & 2 deletions 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::IntRangeType;
use super::range::{IntRangeLibfunc, IntRangeType};
use super::range_check::{RangeCheck96Type, RangeCheckType};
use super::segment_arena::SegmentArenaType;
use super::snapshot::{SnapshotTakeLibfunc, SnapshotType};
Expand All @@ -65,6 +65,7 @@ define_type_hierarchy! {
EcState(EcStateType),
Felt252(Felt252Type),
GasBuiltin(GasBuiltinType),
IntRange(IntRangeType),
BuiltinCosts(BuiltinCostsType),
Uint8(Uint8Type),
Uint16(Uint16Type),
Expand Down Expand Up @@ -95,7 +96,6 @@ define_type_hierarchy! {
Snapshot(SnapshotType),
Bytes31(Bytes31Type),
BoundedInt(BoundedIntType),
IntRange(IntRangeType),
}, CoreTypeConcrete
}

Expand All @@ -117,6 +117,7 @@ define_libfunc_hierarchy! {
Const(ConstLibfunc),
FunctionCall(FunctionCallLibfunc),
Gas(GasLibfunc),
IntRange(IntRangeLibfunc),
Uint8(Uint8Libfunc),
Uint16(Uint16Libfunc),
Uint32(Uint32Libfunc),
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 IntRangeTypeWrapped {
}
}
pub type IntRangeType = GenericTypeArgGenericTypeWrapper<IntRangeTypeWrapped>;

define_libfunc_hierarchy! {
pub enum IntRangeLibfunc {
PopFront(IntRangePopFrontLibfunc),
}, IntRangeConcreteLibfunc
}

/// 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 IntRangePopFrontLibfunc {}
impl SignatureOnlyGenericLibfunc for IntRangePopFrontLibfunc {
const STR_ID: &'static str = "int_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(IntRangeType::id(), ty.clone())?;

Ok(LibfuncSignature {
param_signatures: vec![ParamSignature::new(range_ty.clone())],
branch_signatures: vec![
// Failure.
BranchSignature {
vars: vec![],
ap_change: SierraApChange::Known { new_vars_only: false },
},
// 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 },
},
],
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::IntRange(_) => 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 @@
//! > int_range_pop_front libfunc

//! > test_runner_name
SmallE2ETestRunner

//! > cairo
use core::internal::OptionRev;
// TODO(lior): Move to `range.cairo`.
extern type IntRange<T>;
extern fn int_range_pop_front<T>(range: IntRange<T>) -> OptionRev<(IntRange<T>, T)> nopanic;

fn foo(v: IntRange<i16>) -> OptionRev<(IntRange<i16>, i16)> {
int_range_pop_front(v)
}

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

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

//! > sierra_code
type IntRange<i16> = IntRange<i16> [storable: true, drop: true, dup: true, zero_sized: false];
type i16 = i16 [storable: true, drop: true, dup: true, zero_sized: false];
type Tuple<IntRange<i16>, i16> = Struct<ut@Tuple, IntRange<i16>, 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 core::internal::OptionRev::<(test::IntRange::<core::integer::i16>, core::integer::i16)> = Enum<ut@core::internal::OptionRev::<(test::IntRange::<core::integer::i16>, core::integer::i16)>, Unit, Tuple<IntRange<i16>, i16>> [storable: true, drop: true, dup: true, zero_sized: false];

libfunc int_range_pop_front<i16> = int_range_pop_front<i16>;
libfunc branch_align = branch_align;
libfunc struct_construct<Unit> = struct_construct<Unit>;
libfunc enum_init<core::internal::OptionRev::<(test::IntRange::<core::integer::i16>, core::integer::i16)>, 0> = enum_init<core::internal::OptionRev::<(test::IntRange::<core::integer::i16>, core::integer::i16)>, 0>;
libfunc store_temp<core::internal::OptionRev::<(test::IntRange::<core::integer::i16>, core::integer::i16)>> = store_temp<core::internal::OptionRev::<(test::IntRange::<core::integer::i16>, core::integer::i16)>>;
libfunc struct_construct<Tuple<IntRange<i16>, i16>> = struct_construct<Tuple<IntRange<i16>, i16>>;
libfunc enum_init<core::internal::OptionRev::<(test::IntRange::<core::integer::i16>, core::integer::i16)>, 1> = enum_init<core::internal::OptionRev::<(test::IntRange::<core::integer::i16>, core::integer::i16)>, 1>;

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

test::foo@0([0]: IntRange<i16>) -> (core::internal::OptionRev::<(test::IntRange::<core::integer::i16>, core::integer::i16)>);

0 comments on commit c392a11

Please sign in to comment.