Skip to content

Commit

Permalink
Added impl for i*_try_from_felt252.
Browse files Browse the repository at this point in the history
commit-id:fa36ec75
  • Loading branch information
orizi committed Jul 6, 2023
1 parent 90c54ee commit 6068607
Show file tree
Hide file tree
Showing 12 changed files with 599 additions and 15 deletions.
30 changes: 30 additions & 0 deletions corelib/src/integer.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -1505,26 +1505,51 @@ impl U256TryIntoFelt252 of TryInto<u256, felt252> {
)
}
}
impl Felt252TryIntoI8 of TryInto<felt252, i8> {
fn try_into(self: felt252) -> Option<i8> {
i8_try_from_felt252(self)
}
}
impl I8IntoFelt252 of Into<i8, felt252> {
fn into(self: i8) -> felt252 {
i8_to_felt252(self)
}
}
impl Felt252TryIntoI16 of TryInto<felt252, i16> {
fn try_into(self: felt252) -> Option<i16> {
i16_try_from_felt252(self)
}
}
impl I16IntoFelt252 of Into<i16, felt252> {
fn into(self: i16) -> felt252 {
i16_to_felt252(self)
}
}
impl Felt252TryIntoI32 of TryInto<felt252, i32> {
fn try_into(self: felt252) -> Option<i32> {
i32_try_from_felt252(self)
}
}
impl I32IntoFelt252 of Into<i32, felt252> {
fn into(self: i32) -> felt252 {
i32_to_felt252(self)
}
}
impl Felt252TryIntoI64 of TryInto<felt252, i64> {
fn try_into(self: felt252) -> Option<i64> {
i64_try_from_felt252(self)
}
}
impl I64IntoFelt252 of Into<i64, felt252> {
fn into(self: i64) -> felt252 {
i64_to_felt252(self)
}
}
impl Felt252TryIntoI128 of TryInto<felt252, i128> {
fn try_into(self: felt252) -> Option<i128> {
i128_try_from_felt252(self)
}
}
impl I128IntoFelt252 of Into<i128, felt252> {
fn into(self: i128) -> felt252 {
i128_to_felt252(self)
Expand Down Expand Up @@ -1843,6 +1868,7 @@ impl U256Zeroable of Zeroable<u256> {
extern type i8;
impl NumericLiterali8 of NumericLiteral<i8>;
extern fn i8_const<value>() -> i8 nopanic;
extern fn i8_try_from_felt252(a: felt252) -> Option<i8> implicits(RangeCheck) nopanic;
extern fn i8_to_felt252(a: i8) -> felt252 nopanic;

extern fn i8_is_zero(a: i8) -> IsZeroResult<i8> implicits() nopanic;
Expand All @@ -1863,6 +1889,7 @@ impl I8PartialEq of PartialEq<i8> {
extern type i16;
impl NumericLiterali16 of NumericLiteral<i16>;
extern fn i16_const<value>() -> i16 nopanic;
extern fn i16_try_from_felt252(a: felt252) -> Option<i16> implicits(RangeCheck) nopanic;
extern fn i16_to_felt252(a: i16) -> felt252 nopanic;

extern fn i16_is_zero(a: i16) -> IsZeroResult<i16> implicits() nopanic;
Expand All @@ -1883,6 +1910,7 @@ impl I16PartialEq of PartialEq<i16> {
extern type i32;
impl NumericLiterali32 of NumericLiteral<i32>;
extern fn i32_const<value>() -> i32 nopanic;
extern fn i32_try_from_felt252(a: felt252) -> Option<i32> implicits(RangeCheck) nopanic;
extern fn i32_to_felt252(a: i32) -> felt252 nopanic;

extern fn i32_is_zero(a: i32) -> IsZeroResult<i32> implicits() nopanic;
Expand All @@ -1903,6 +1931,7 @@ impl I32PartialEq of PartialEq<i32> {
extern type i64;
impl NumericLiterali64 of NumericLiteral<i64>;
extern fn i64_const<value>() -> i64 nopanic;
extern fn i64_try_from_felt252(a: felt252) -> Option<i64> implicits(RangeCheck) nopanic;
extern fn i64_to_felt252(a: i64) -> felt252 nopanic;

extern fn i64_is_zero(a: i64) -> IsZeroResult<i64> implicits() nopanic;
Expand All @@ -1923,6 +1952,7 @@ impl I64PartialEq of PartialEq<i64> {
extern type i128;
impl NumericLiterali128 of NumericLiteral<i128>;
extern fn i128_const<value>() -> i128 nopanic;
extern fn i128_try_from_felt252(a: felt252) -> Option<i128> implicits(RangeCheck) nopanic;
extern fn i128_to_felt252(a: i128) -> felt252 nopanic;

extern fn i128_is_zero(a: i128) -> IsZeroResult<i128> implicits() nopanic;
Expand Down
43 changes: 43 additions & 0 deletions corelib/src/test/integer_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -1125,32 +1125,75 @@ fn test_u128_byte_reverse() {
fn test_i8_operators() {
assert_eq(@1_i8, @1_i8, '1 == 1');
assert_ne(@1_i8, @2_i8, '1 != 2');
assert_eq(@0x7f_felt252.try_into().unwrap(), @0x7f_i8, '0x7f is not i8');
let v: Option<i8> = 0x80_felt252.try_into();
assert(v.is_none(), '0x80 is i8');
let v: Option<i8> = (-0x80_felt252).try_into();
assert(v.is_some(), '-0x80 is not i8');
let v: Option<i8> = (-0x81_felt252).try_into();
assert(v.is_none(), '-0x81 is i8');
}


#[test]
fn test_i16_operators() {
assert_eq(@1_i16, @1_i16, '1 == 1');
assert_ne(@1_i16, @2_i16, '1 != 2');
assert_eq(@0x7fff_felt252.try_into().unwrap(), @0x7fff_i16, '0x7fff is not i16');
let v: Option<i16> = 0x8000_felt252.try_into();
assert(v.is_none(), '0x8000 is i16');
let v: Option<i16> = (-0x8000_felt252).try_into();
assert(v.is_some(), '-0x8000 is not i16');
let v: Option<i16> = (-0x8001_felt252).try_into();
assert(v.is_none(), '-0x8001 is i16');
}


#[test]
fn test_i32_operators() {
assert_eq(@1_i32, @1_i32, '1 == 1');
assert_ne(@1_i32, @2_i32, '1 != 2');
assert_eq(@0x7fffffff_felt252.try_into().unwrap(), @0x7fffffff_i32, '0x7fffffff is not i32');
let v: Option<i32> = 0x80000000_felt252.try_into();
assert(v.is_none(), '0x80000000 is i32');
let v: Option<i32> = (-0x80000000_felt252).try_into();
assert(v.is_some(), '-0x80000000 is not i32');
let v: Option<i32> = (-0x80000001_felt252).try_into();
assert(v.is_none(), '-0x80000001 is i32');
}


#[test]
fn test_i64_operators() {
assert_eq(@1_i64, @1_i64, '1 == 1');
assert_ne(@1_i64, @2_i64, '1 != 2');
assert_eq(
@0x7fffffffffffffff_felt252.try_into().unwrap(),
@0x7fffffffffffffff_i64,
'-0x7fffffffffffffff is not i64'
);
let v: Option<i64> = 0x8000000000000000_felt252.try_into();
assert(v.is_none(), '0x8000000000000000 is i64');
let v: Option<i64> = (-0x8000000000000000_felt252).try_into();
assert(v.is_some(), '-0x8000000000000000 is not i64');
let v: Option<i64> = (-0x8000000000000001_felt252).try_into();
assert(v.is_none(), '-0x8000000000000001 is i64');
}


#[test]
fn test_i128_operators() {
assert_eq(@1_i128, @1_i128, '1 == 1');
assert_ne(@1_i128, @2_i128, '1 != 2');
assert_eq(
@0x7fffffffffffffffffffffffffffffff_felt252.try_into().unwrap(),
@0x7fffffffffffffffffffffffffffffff_i128,
'0x7f..f is not i128'
);
let v: Option<i128> = 0x80000000000000000000000000000000_felt252.try_into();
assert(v.is_none(), '0x80..0 is i128');
let v: Option<i128> = (-0x80000000000000000000000000000000_felt252).try_into();
assert(v.is_some(), '-0x80..0 is not i128');
let v: Option<i128> = (-0x80000000000000000000000000000001_felt252).try_into();
assert(v.is_none(), '-0x80..01 is i128');
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ pub fn core_libfunc_ap_change<InfoProvider: InvocationApChangeInfoProvider>(
CoreConcreteLibfunc::Sint64(libfunc) => sint_ap_change(libfunc),
CoreConcreteLibfunc::Sint128(libfunc) => match libfunc {
Sint128Concrete::Equal(_) => vec![ApChange::Known(1), ApChange::Known(1)],
Sint128Concrete::FromFelt252(_) => vec![ApChange::Known(1), ApChange::Known(6)],
Sint128Concrete::FromFelt252(_) => vec![ApChange::Known(2), ApChange::Known(7)],
Sint128Concrete::Const(_) | Sint128Concrete::ToFelt252(_) => {
vec![ApChange::Known(0)]
}
Expand Down Expand Up @@ -316,7 +316,7 @@ fn sint_ap_change<TSintTraits: SintTraits + IntMulTraits + IsZeroTraits>(
match libfunc {
SintConcrete::Const(_) | SintConcrete::ToFelt252(_) => vec![ApChange::Known(0)],
SintConcrete::Equal(_) => vec![ApChange::Known(1), ApChange::Known(1)],
SintConcrete::FromFelt252(_) => vec![ApChange::Known(2), ApChange::Known(7)],
SintConcrete::FromFelt252(_) => vec![ApChange::Known(3), ApChange::Known(7)],
SintConcrete::IsZero(_) => vec![ApChange::Known(0), ApChange::Known(0)],
SintConcrete::WideMul(_) => vec![ApChange::Known(0)],
}
Expand Down
8 changes: 4 additions & 4 deletions crates/cairo-lang-sierra-gas/src/core_libfunc_cost_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,8 +619,8 @@ fn sint_libfunc_cost<TSintTraits: SintTraits + IsZeroTraits + IntMulTraits>(
}
SintConcrete::FromFelt252(_) => {
vec![
ConstCost { steps: 4, holes: 0, range_checks: 2 }.into(),
ConstCost { steps: 10, holes: 0, range_checks: 3 }.into(),
ConstCost { steps: 5, holes: 0, range_checks: 2 }.into(),
ConstCost { steps: 12, holes: 0, range_checks: 3 }.into(),
]
}
SintConcrete::IsZero(_) => vec![ConstCost::steps(1).into(), ConstCost::steps(1).into()],
Expand All @@ -636,8 +636,8 @@ fn s128_libfunc_cost(libfunc: &Sint128Concrete) -> Vec<BranchCost> {
}
Sint128Concrete::FromFelt252(_) => {
vec![
ConstCost { steps: 2, holes: 0, range_checks: 1 }.into(),
ConstCost { steps: 11, holes: 0, range_checks: 3 }.into(),
ConstCost { steps: 3, holes: 0, range_checks: 1 }.into(),
ConstCost { steps: 12, holes: 0, range_checks: 3 }.into(),
]
}
Sint128Concrete::IsZero(_) => {
Expand Down
81 changes: 77 additions & 4 deletions crates/cairo-lang-sierra-to-casm/src/invocations/int/signed.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,93 @@
use cairo_felt::Felt252;
use cairo_lang_casm::builder::CasmBuilder;
use cairo_lang_casm::casm_build_extend;
use cairo_lang_sierra::extensions::int::signed::{SintConcrete, SintTraits};
use cairo_lang_sierra::extensions::int::IntMulTraits;
use cairo_lang_sierra::extensions::is_zero::IsZeroTraits;
use num_bigint::{BigInt, ToBigInt};

use super::{build_const, build_small_wide_mul};
use crate::invocations::{misc, CompiledInvocation, CompiledInvocationBuilder, InvocationError};
use super::{add_input_variables, build_const, build_small_wide_mul};
use crate::invocations::misc::validate_under_limit;
use crate::invocations::{
get_non_fallthrough_statement_id, misc, CompiledInvocation, CompiledInvocationBuilder,
CostValidationInfo, InvocationError,
};

/// Handles a signed integer conversion from felt252.
pub fn build_sint_from_felt252(
builder: CompiledInvocationBuilder<'_>,
lower_limit: i128,
upper_limit: i128,
) -> Result<CompiledInvocation, InvocationError> {
let [range_check, value] = builder.try_get_single_cells()?;
let failure_handle_statement_id = get_non_fallthrough_statement_id(&builder);
let mut casm_builder = CasmBuilder::default();
add_input_variables! {casm_builder,
buffer(2) range_check;
deref value;
};
let range_size: BigInt = BigInt::from(upper_limit) - BigInt::from(lower_limit) + 1;
casm_build_extend! {casm_builder,
let orig_range_check = range_check;
const positive_range_fixer = -BigInt::from(lower_limit);
let canonical_value = value + positive_range_fixer;
tempvar is_in_range;
const range_size_imm = range_size.clone();
hint TestLessThan {lhs: canonical_value, rhs: range_size_imm} into {dst: is_in_range};
jump IsInRange if is_in_range != 0;
const upper_limit_plus_one = (BigInt::from(upper_limit) + 1) as BigInt;
tempvar shifted_value = value - upper_limit_plus_one;
}
let auxiliary_vars: [_; 5] = std::array::from_fn(|_| casm_builder.alloc_var(false));
validate_under_limit::<2>(
&mut casm_builder,
&(-Felt252::from(range_size)).to_biguint().to_bigint().unwrap(),
shifted_value,
range_check,
&auxiliary_vars,
);
casm_build_extend! {casm_builder,
jump Done;
IsInRange:
tempvar rc_val = canonical_value;
assert rc_val = *(range_check++);
}
// For i128, the previous range check already made sure the value is in range.
if lower_limit != i128::MIN || upper_limit != i128::MAX {
casm_build_extend! {casm_builder,
// value + 2**128 - upper_limit - 1 < 2**128 ==> value <= upper_limit
const fixer_limit = (BigInt::from(2).pow(128) - upper_limit - 1) as BigInt;
tempvar rc_val = value + fixer_limit;
assert rc_val = *(range_check++);
};
}
Ok(builder.build_from_casm_builder(
casm_builder,
[
("Fallthrough", &[&[range_check], &[value]], None),
("Done", &[&[range_check]], Some(failure_handle_statement_id)),
],
CostValidationInfo {
range_check_info: Some((orig_range_check, range_check)),
extra_costs: None,
},
))
}

/// Builds instructions for Sierra i8/i16/i32/i64 operations.
pub fn build_sint<TSintTraits: SintTraits + IntMulTraits + IsZeroTraits>(
pub fn build_sint<
TSintTraits: SintTraits + IntMulTraits + IsZeroTraits,
const LOWER_LIMIT: i128,
const UPPER_LIMIT: i128,
>(
libfunc: &SintConcrete<TSintTraits>,
builder: CompiledInvocationBuilder<'_>,
) -> Result<CompiledInvocation, InvocationError> {
match libfunc {
SintConcrete::Const(libfunc) => build_const(libfunc, builder),
SintConcrete::Equal(_) => misc::build_cell_eq(builder),
SintConcrete::ToFelt252(_) => misc::build_identity(builder),
SintConcrete::FromFelt252(_) => todo!(),
SintConcrete::FromFelt252(_) => build_sint_from_felt252(builder, LOWER_LIMIT, UPPER_LIMIT),
SintConcrete::IsZero(_) => misc::build_is_zero(builder),
SintConcrete::WideMul(_) => build_small_wide_mul(builder),
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use cairo_lang_sierra::extensions::int::signed128::Sint128Concrete;

use super::signed::build_sint_from_felt252;
use super::{build_const, CompiledInvocation, CompiledInvocationBuilder, InvocationError};
use crate::invocations::misc;

Expand All @@ -11,7 +12,7 @@ pub fn build(
match libfunc {
Sint128Concrete::IsZero(_) => misc::build_is_zero(builder),
Sint128Concrete::Const(libfunc) => build_const(libfunc, builder),
Sint128Concrete::FromFelt252(_) => todo!(),
Sint128Concrete::FromFelt252(_) => build_sint_from_felt252(builder, i128::MIN, i128::MAX),
Sint128Concrete::ToFelt252(_) => misc::build_identity(builder),
Sint128Concrete::Equal(_) => misc::build_cell_eq(builder),
}
Expand Down
22 changes: 18 additions & 4 deletions crates/cairo-lang-sierra-to-casm/src/invocations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,10 +597,24 @@ pub fn compile_invocation(
CoreConcreteLibfunc::Uint128(libfunc) => int::unsigned128::build(libfunc, builder),
CoreConcreteLibfunc::Uint256(libfunc) => int::unsigned256::build(libfunc, builder),
CoreConcreteLibfunc::Uint512(libfunc) => int::unsigned512::build(libfunc, builder),
CoreConcreteLibfunc::Sint8(libfunc) => int::signed::build_sint(libfunc, builder),
CoreConcreteLibfunc::Sint16(libfunc) => int::signed::build_sint(libfunc, builder),
CoreConcreteLibfunc::Sint32(libfunc) => int::signed::build_sint(libfunc, builder),
CoreConcreteLibfunc::Sint64(libfunc) => int::signed::build_sint(libfunc, builder),
CoreConcreteLibfunc::Sint8(libfunc) => {
int::signed::build_sint::<_, { i8::MIN as i128 }, { i8::MAX as i128 }>(libfunc, builder)
}
CoreConcreteLibfunc::Sint16(libfunc) => {
int::signed::build_sint::<_, { i16::MIN as i128 }, { i16::MAX as i128 }>(
libfunc, builder,
)
}
CoreConcreteLibfunc::Sint32(libfunc) => {
int::signed::build_sint::<_, { i32::MIN as i128 }, { i32::MAX as i128 }>(
libfunc, builder,
)
}
CoreConcreteLibfunc::Sint64(libfunc) => {
int::signed::build_sint::<_, { i64::MIN as i128 }, { i64::MAX as i128 }>(
libfunc, builder,
)
}
CoreConcreteLibfunc::Sint128(libfunc) => int::signed128::build(libfunc, builder),
CoreConcreteLibfunc::Gas(libfunc) => gas::build(libfunc, builder),
CoreConcreteLibfunc::BranchAlign(_) => misc::build_branch_align(builder),
Expand Down
Loading

0 comments on commit 6068607

Please sign in to comment.