diff --git a/src/libfuncs.rs b/src/libfuncs.rs index 83df646b4..cfe523f90 100644 --- a/src/libfuncs.rs +++ b/src/libfuncs.rs @@ -41,6 +41,7 @@ pub mod mem; pub mod nullable; pub mod pedersen; pub mod poseidon; +pub mod sint128; pub mod sint16; pub mod sint32; pub mod sint64; @@ -215,7 +216,9 @@ where CoreConcreteLibfunc::Sint64(info) => { self::sint64::build(context, registry, entry, location, helper, metadata, info) } - CoreConcreteLibfunc::Sint128(_) => todo!(), + CoreConcreteLibfunc::Sint128(info) => { + self::sint128::build(context, registry, entry, location, helper, metadata, info) + } CoreConcreteLibfunc::Bytes31(_) => todo!(), } } diff --git a/src/libfuncs/sint128.rs b/src/libfuncs/sint128.rs new file mode 100644 index 000000000..0ab8af525 --- /dev/null +++ b/src/libfuncs/sint128.rs @@ -0,0 +1,767 @@ +//! # `i128`-related libfuncs +use super::{LibfuncBuilder, LibfuncHelper}; + +use crate::{ + error::{ + libfuncs::{Error, Result}, + CoreTypeBuilderError, + }, + metadata::MetadataStorage, + types::TypeBuilder, + utils::ProgramRegistryExt, +}; +use cairo_lang_sierra::{ + extensions::{ + int::{ + signed128::{Sint128Concrete, Sint128Traits}, + IntConstConcreteLibfunc, IntOperationConcreteLibfunc, IntOperator, + }, + lib_func::SignatureOnlyConcreteLibfunc, + ConcreteLibfunc, GenericLibfunc, GenericType, + }, + program_registry::ProgramRegistry, +}; +use melior::{ + dialect::{ + arith::{self, CmpiPredicate}, + cf, llvm, + }, + ir::{ + attribute::{DenseI64ArrayAttribute, IntegerAttribute}, + operation::OperationBuilder, + r#type::IntegerType, + Attribute, Block, Location, Value, ValueLike, + }, + Context, +}; + +/// Select and call the correct libfunc builder function from the selector. +pub fn build<'ctx, 'this, TType, TLibfunc>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + selector: &Sint128Concrete, +) -> Result<()> +where + TType: GenericType, + TLibfunc: GenericLibfunc, + ::Concrete: TypeBuilder, + ::Concrete: LibfuncBuilder, +{ + match selector { + Sint128Concrete::Const(info) => { + build_const(context, registry, entry, location, helper, metadata, info) + } + Sint128Concrete::Operation(info) => { + build_operation(context, registry, entry, location, helper, info) + } + Sint128Concrete::Equal(info) => { + build_equal(context, registry, entry, location, helper, info) + } + Sint128Concrete::ToFelt252(info) => { + build_to_felt252(context, registry, entry, location, helper, metadata, info) + } + Sint128Concrete::FromFelt252(info) => { + build_from_felt252(context, registry, entry, location, helper, metadata, info) + } + Sint128Concrete::IsZero(info) => { + build_is_zero(context, registry, entry, location, helper, info) + } + Sint128Concrete::Diff(info) => build_diff(context, registry, entry, location, helper, info), + } +} + +/// Generate MLIR operations for the `i128_const` libfunc. +pub fn build_const<'ctx, 'this, TType, TLibfunc>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &IntConstConcreteLibfunc, +) -> Result<()> +where + TType: GenericType, + TLibfunc: GenericLibfunc, + ::Concrete: TypeBuilder, + ::Concrete: LibfuncBuilder, +{ + let value = info.c; + let value_ty = registry.build_type( + context, + helper, + registry, + metadata, + &info.signature.branch_signatures[0].vars[0].ty, + )?; + + let op0 = entry.append_operation(arith::constant( + context, + Attribute::parse(context, &format!("{value} : {value_ty}")).unwrap(), + location, + )); + entry.append_operation(helper.br(0, &[op0.result(0)?.into()], location)); + + Ok(()) +} + +/// Generate MLIR operations for the i128 operation libfunc. +pub fn build_operation<'ctx, 'this, TType, TLibfunc>( + context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + info: &IntOperationConcreteLibfunc, +) -> Result<()> +where + TType: GenericType, + TLibfunc: GenericLibfunc, + ::Concrete: TypeBuilder, + ::Concrete: LibfuncBuilder, +{ + let range_check: Value = entry.argument(0)?.into(); + let lhs: Value = entry.argument(1)?.into(); + let rhs: Value = entry.argument(2)?.into(); + + let op_name = match info.operator { + IntOperator::OverflowingAdd => "llvm.intr.sadd.with.overflow", + IntOperator::OverflowingSub => "llvm.intr.ssub.with.overflow", + }; + + let values_type = lhs.r#type(); + + let result_type = llvm::r#type::r#struct( + context, + &[values_type, IntegerType::new(context, 1).into()], + false, + ); + + let result = entry + .append_operation( + OperationBuilder::new(op_name, location) + .add_operands(&[lhs, rhs]) + .add_results(&[result_type]) + .build()?, + ) + .result(0)? + .into(); + + let op_result = entry + .append_operation(llvm::extract_value( + context, + result, + DenseI64ArrayAttribute::new(context, &[0]), + values_type, + location, + )) + .result(0)? + .into(); + + // Create a const operation to get the 0 value to compare against + let zero_const = entry + .append_operation(arith::constant( + context, + IntegerAttribute::new(0.into(), values_type).into(), + location, + )) + .result(0)? + .into(); + // Check if the result is positive + let is_positive = entry + .append_operation(arith::cmpi( + context, + CmpiPredicate::Sge, + op_result, + zero_const, + location, + )) + .result(0)? + .into(); + + // Check overflow flag + let op_overflow = entry + .append_operation(llvm::extract_value( + context, + result, + DenseI64ArrayAttribute::new(context, &[1]), + IntegerType::new(context, 1).into(), + location, + )) + .result(0)? + .into(); + + let block_not_overflow = helper.append_block(Block::new(&[])); + let block_overflow = helper.append_block(Block::new(&[])); + + // The libfunc has three possible outputs: In Range, Overflow & Underflow + entry.append_operation(cf::cond_br( + context, + op_overflow, + block_overflow, + block_not_overflow, + &[], + &[], + location, + )); + // Check wether the result is positive to distinguish between undeflowing & overflowing results + block_overflow.append_operation(helper.cond_br( + context, + is_positive, + [1, 2], + [&[range_check, op_result], &[range_check, op_result]], + location, + )); + // No Oveflow/Underflow -> In range result + block_not_overflow.append_operation(helper.br(0, &[range_check, op_result], location)); + Ok(()) +} + +/// Generate MLIR operations for the `i128_eq` libfunc. +pub fn build_equal<'ctx, 'this, TType, TLibfunc>( + context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> +where + TType: GenericType, + TLibfunc: GenericLibfunc, + ::Concrete: TypeBuilder, + ::Concrete: LibfuncBuilder, +{ + let arg0: Value = entry.argument(0)?.into(); + let arg1: Value = entry.argument(1)?.into(); + + let op0 = entry.append_operation(arith::cmpi( + context, + CmpiPredicate::Eq, + arg0, + arg1, + location, + )); + + entry.append_operation(helper.cond_br( + context, + op0.result(0)?.into(), + [1, 0], + [&[]; 2], + location, + )); + + Ok(()) +} + +/// Generate MLIR operations for the `i128_is_zero` libfunc. +pub fn build_is_zero<'ctx, 'this, TType, TLibfunc>( + context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> +where + TType: GenericType, + TLibfunc: GenericLibfunc, + ::Concrete: TypeBuilder, + ::Concrete: LibfuncBuilder, +{ + let arg0: Value = entry.argument(0)?.into(); + + let op = entry.append_operation(arith::constant( + context, + IntegerAttribute::new(0, arg0.r#type()).into(), + location, + )); + let const_0 = op.result(0)?.into(); + + let condition = entry + .append_operation(arith::cmpi( + context, + CmpiPredicate::Eq, + arg0, + const_0, + location, + )) + .result(0)? + .into(); + + entry.append_operation(helper.cond_br(context, condition, [0, 1], [&[], &[arg0]], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `i128_to_felt252` libfunc. +pub fn build_to_felt252<'ctx, 'this, TType, TLibfunc>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> +where + TType: GenericType, + TLibfunc: GenericLibfunc, + ::Concrete: TypeBuilder, + ::Concrete: LibfuncBuilder, +{ + let felt252_ty = registry.build_type( + context, + helper, + registry, + metadata, + &info.branch_signatures()[0].vars[0].ty, + )?; + let value: Value = entry.argument(0)?.into(); + + let result = entry + .append_operation(arith::extui(value, felt252_ty, location)) + .result(0)? + .into(); + + entry.append_operation(helper.br(0, &[result], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `i128_from_felt252` libfunc. +pub fn build_from_felt252<'ctx, 'this, TType, TLibfunc>( + context: &'ctx Context, + registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + metadata: &mut MetadataStorage, + info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> +where + TType: GenericType, + TLibfunc: GenericLibfunc, + ::Concrete: TypeBuilder, + ::Concrete: LibfuncBuilder, +{ + let range_check: Value = entry.argument(0)?.into(); + let value: Value = entry.argument(1)?.into(); + + let felt252_ty = registry.build_type( + context, + helper, + registry, + metadata, + &info.param_signatures()[1].ty, + )?; + let result_ty = registry.build_type( + context, + helper, + registry, + metadata, + &info.branch_signatures()[0].vars[1].ty, + )?; + + let const_max = entry + .append_operation(arith::constant( + context, + Attribute::parse(context, &format!("{} : {}", i128::MAX, felt252_ty)).unwrap(), + location, + )) + .result(0)? + .into(); + + let is_ule = entry + .append_operation(arith::cmpi( + context, + CmpiPredicate::Ule, + value, + const_max, + location, + )) + .result(0)? + .into(); + + let block_success = helper.append_block(Block::new(&[])); + let block_failure = helper.append_block(Block::new(&[])); + + entry.append_operation(cf::cond_br( + context, + is_ule, + block_success, + block_failure, + &[], + &[], + location, + )); + + let value = block_success + .append_operation(arith::trunci(value, result_ty, location)) + .result(0)? + .into(); + block_success.append_operation(helper.br(0, &[range_check, value], location)); + + block_failure.append_operation(helper.br(1, &[range_check], location)); + + Ok(()) +} + +/// Generate MLIR operations for the `i128_diff` libfunc. +pub fn build_diff<'ctx, 'this, TType, TLibfunc>( + context: &'ctx Context, + _registry: &ProgramRegistry, + entry: &'this Block<'ctx>, + location: Location<'ctx>, + helper: &LibfuncHelper<'ctx, 'this>, + _info: &SignatureOnlyConcreteLibfunc, +) -> Result<()> +where + TType: GenericType, + TLibfunc: GenericLibfunc, + ::Concrete: TypeBuilder, + ::Concrete: LibfuncBuilder, +{ + let range_check: Value = entry.argument(0)?.into(); + let lhs: Value = entry.argument(1)?.into(); + let rhs: Value = entry.argument(2)?.into(); + + // Check if lhs >= rhs + let is_ge = entry + .append_operation(arith::cmpi(context, CmpiPredicate::Sge, lhs, rhs, location)) + .result(0)? + .into(); + + let result = entry + .append_operation(arith::subi(lhs, rhs, location)) + .result(0)? + .into(); + + entry.append_operation(helper.cond_br( + context, + is_ge, + [0, 1], + [&[range_check, result], &[range_check, result]], + location, + )); + + Ok(()) +} + +#[cfg(test)] +mod test { + use crate::{ + utils::test::{jit_enum, jit_panic, jit_struct, load_cairo, run_program_assert_output}, + values::JITValue, + }; + use cairo_lang_sierra::program::Program; + use lazy_static::lazy_static; + use starknet_types_core::felt::Felt; + + lazy_static! { + static ref I128_OVERFLOWING_ADD: (String, Program) = load_cairo! { + fn run_test(lhs: i128, rhs: i128) -> i128 { + lhs + rhs + } + }; + static ref I128_OVERFLOWING_SUB: (String, Program) = load_cairo! { + fn run_test(lhs: i128, rhs: i128) -> i128 { + lhs - rhs + } + }; + static ref I128_EQUAL: (String, Program) = load_cairo! { + fn run_test(lhs: i128, rhs: i128) -> bool { + lhs == rhs + } + }; + static ref I128_IS_ZERO: (String, Program) = load_cairo! { + use zeroable::IsZeroResult; + + extern fn i128_is_zero(a: i128) -> IsZeroResult implicits() nopanic; + + fn run_test(value: i128) -> bool { + match i128_is_zero(value) { + IsZeroResult::Zero(_) => true, + IsZeroResult::NonZero(_) => false, + } + } + }; + } + + #[test] + fn i128_const_min() { + let program = load_cairo!( + fn run_test() -> i128 { + -170141183460469231731687303715884105728_i128 + } + ); + + run_program_assert_output(&program, "run_test", &[], &[i128::MIN.into()]); + } + + #[test] + fn i128_const_max() { + let program = load_cairo!( + fn run_test() -> i128 { + 170141183460469231731687303715884105727_i128 + } + ); + + run_program_assert_output(&program, "run_test", &[], &[(i128::MAX).into()]); + } + + #[test] + fn i128_to_felt252() { + let program = load_cairo!( + use traits::Into; + + fn run_test() -> felt252 { + 2_i128.into() + } + ); + + run_program_assert_output(&program, "run_test", &[], &[Felt::from(2).into()]); + } + + #[test] + fn i128_from_felt252() { + let program = load_cairo!( + use traits::TryInto; + + fn run_test() -> (Option, Option) { + ( + 170141183460469231731687303715884105727.try_into(), + 170141183460469231731687303715884105728.try_into(), + ) + } + ); + + run_program_assert_output( + &program, + "run_test", + &[], + &[jit_struct!( + jit_enum!(0, 170141183460469231731687303715884105727i128.into()), + jit_enum!(1, jit_struct!()), + )], + ); + } + + #[test] + fn i128_overflowing_add() { + #[track_caller] + fn run(lhs: i128, rhs: i128) { + let program = &I128_OVERFLOWING_ADD; + let error = Felt::from_bytes_be_slice(b"i128_add Overflow"); + + let add = lhs.checked_add(rhs); + + match add { + Some(result) => { + run_program_assert_output( + program, + "run_test", + &[lhs.into(), rhs.into()], + &[jit_enum!(0, jit_struct!(result.into()))], + ); + } + None => { + run_program_assert_output( + program, + "run_test", + &[lhs.into(), rhs.into()], + &[jit_panic!(JITValue::Felt252(error))], + ); + } + } + } + + const MAX: i128 = i128::MAX; + + run(0, 0); + run(0, 1); + run(0, MAX - 1); + run(0, MAX); + + run(1, 0); + run(1, 1); + run(1, MAX - 1); + run(1, MAX); + + run(MAX - 1, 0); + run(MAX - 1, 1); + run(MAX - 1, MAX - 1); + run(MAX - 1, MAX); + + run(MAX, 0); + run(MAX, 1); + run(MAX, MAX - 1); + run(MAX, MAX); + } + + #[test] + fn i128_overflowing_sub() { + #[track_caller] + fn run(lhs: i128, rhs: i128) { + let program = &I128_OVERFLOWING_SUB; + let error = Felt::from_bytes_be_slice(b"i128_sub Overflow"); + + let add = lhs.checked_sub(rhs); + + match add { + Some(result) => { + run_program_assert_output( + program, + "run_test", + &[lhs.into(), rhs.into()], + &[jit_enum!(0, jit_struct!(result.into()))], + ); + } + None => { + run_program_assert_output( + program, + "run_test", + &[lhs.into(), rhs.into()], + &[jit_panic!(JITValue::Felt252(error))], + ); + } + } + } + + const MAX: i128 = i128::MAX; + + run(0, 0); + run(0, 1); + run(0, MAX - 1); + run(0, MAX); + + run(1, 0); + run(1, 1); + run(1, MAX - 1); + run(1, MAX); + + run(MAX - 1, 0); + run(MAX - 1, 1); + run(MAX - 1, MAX - 1); + run(MAX - 1, MAX); + + run(MAX, 0); + run(MAX, 1); + run(MAX, MAX - 1); + run(MAX, MAX); + } + + #[test] + fn i128_equal() { + let program = &I128_EQUAL; + + run_program_assert_output( + program, + "run_test", + &[0i128.into(), 0i128.into()], + &[jit_enum!(1, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[1i128.into(), 0i128.into()], + &[jit_enum!(0, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[0i128.into(), 1i128.into()], + &[jit_enum!(0, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[1i128.into(), 1i128.into()], + &[jit_enum!(1, jit_struct!())], + ); + } + + #[test] + fn i128_is_zero() { + let program = &I128_IS_ZERO; + + run_program_assert_output( + program, + "run_test", + &[0i128.into()], + &[jit_enum!(1, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[1i128.into()], + &[jit_enum!(0, jit_struct!())], + ); + } + + #[test] + fn i128_safe_divmod() { + let program = &I128_IS_ZERO; + + run_program_assert_output( + program, + "run_test", + &[0i128.into(), 0i128.into()], + &[jit_enum!(1, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[0i128.into(), 1i128.into()], + &[jit_enum!(1, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[0i128.into(), i128::MAX.into()], + &[jit_enum!(1, jit_struct!())], + ); + + run_program_assert_output( + program, + "run_test", + &[1i128.into(), 0i128.into()], + &[jit_enum!(0, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[1i128.into(), 1i128.into()], + &[jit_enum!(0, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[1i128.into(), i128::MAX.into()], + &[jit_enum!(0, jit_struct!())], + ); + + run_program_assert_output( + program, + "run_test", + &[i128::MAX.into(), 0i128.into()], + &[jit_enum!(0, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[i128::MAX.into(), 1i128.into()], + &[jit_enum!(0, jit_struct!())], + ); + run_program_assert_output( + program, + "run_test", + &[i128::MAX.into(), i128::MAX.into()], + &[jit_enum!(0, jit_struct!())], + ); + } +} diff --git a/tests/cases.rs b/tests/cases.rs index adb8e470a..1eabb8812 100644 --- a/tests/cases.rs +++ b/tests/cases.rs @@ -62,6 +62,9 @@ mod common; #[test_case("tests/cases/sint/i64_diff.cairo")] #[test_case("tests/cases/sint/i64_add_sub.cairo")] #[test_case("tests/cases/sint/i64_wide_mul.cairo")] +// sint128 +#[test_case("tests/cases/sint/i128_diff.cairo")] +#[test_case("tests/cases/sint/i128_add_sub.cairo")] // structs #[test_case("tests/cases/structs/basic.cairo")] #[test_case("tests/cases/structs/bigger.cairo")] diff --git a/tests/cases/sint/eq.cairo b/tests/cases/sint/eq.cairo index 67e76469e..2f3b8fbf4 100644 --- a/tests/cases/sint/eq.cairo +++ b/tests/cases/sint/eq.cairo @@ -3,6 +3,7 @@ fn main() -> ( bool, bool, bool, bool, bool, bool, bool, bool, bool, + bool, bool, bool, ) { ( integer::i8_eq(17, 71), @@ -20,5 +21,9 @@ fn main() -> ( integer::i64_eq(17, 71), integer::i64_eq(17, 17), integer::i64_eq(2, -2), + + integer::i128_eq(17, 71), + integer::i128_eq(17, 17), + integer::i128_eq(2, -2), ) } diff --git a/tests/cases/sint/i128_add_sub.cairo b/tests/cases/sint/i128_add_sub.cairo new file mode 100644 index 000000000..49b35a30b --- /dev/null +++ b/tests/cases/sint/i128_add_sub.cairo @@ -0,0 +1,43 @@ +use integer::{i128_overflowing_add_impl, i128_overflowing_sub_impl, SignedIntegerResult}; + +fn overflowing_add(lhs: i128, rhs: i128) -> (i128, i128) { + match i128_overflowing_add_impl(lhs, rhs) { + SignedIntegerResult::InRange(res) => (res, 0), + SignedIntegerResult::Underflow(res) => (res, 1), + SignedIntegerResult::Overflow(res) =>(res, 2), + } +} + +fn overflowing_sub(lhs: i128, rhs: i128) -> (i128, i128) { + match i128_overflowing_sub_impl(lhs, rhs) { + SignedIntegerResult::InRange(res) => (res, 0), + SignedIntegerResult::Underflow(res) => (res, 1), + SignedIntegerResult::Overflow(res) =>(res, 2), + } +} + +fn main() -> ( + (i128, i128, i128, i128, i128, i128, i128, i128), + (i128, i128, i128, i128, i128, i128, i128, i128), +) { + // In range additions + let (res_a, flag_a) = overflowing_add(16, 1); + let (res_b, flag_b) = overflowing_add(-1, -16); + // Underflow + let (res_c, flag_c) = overflowing_add(-100000000000000000000000000000000000000, -100000000000000000000000000000000000000); + // Overflow + let (res_d, flag_d) = overflowing_add(100000000000000000000000000000000000000, 100000000000000000000000000000000000000); + + // In range subtractions + let (res_e, flag_e) = overflowing_sub(16, 1); + let (res_f, flag_f) = overflowing_sub(1, 16); + // Underflow + let (res_g, flag_g) = overflowing_sub(-100000000000000000000000000000000000000, 100000000000000000000000000000000000000); + // Overflow + let (res_h, flag_h) = overflowing_sub(100000000000000000000000000000000000000, -100000000000000000000000000000000000000); + + ( + ( res_a, flag_a, res_b, flag_b, res_c, flag_c, res_d, flag_d ), + ( res_e, flag_e, res_f, flag_f, res_g, flag_g, res_h, flag_h ), + ) +} diff --git a/tests/cases/sint/i128_diff.cairo b/tests/cases/sint/i128_diff.cairo new file mode 100644 index 000000000..1453ad0f6 --- /dev/null +++ b/tests/cases/sint/i128_diff.cairo @@ -0,0 +1,24 @@ +fn diff(a: i128, b: i128) -> (u128, u128) { + match integer::i128_diff(a, b) { + Result::Ok(r) => (r, 0), + Result::Err(r) => (r, 1), + } +} + +fn main() -> ( + (u128, u128), (u128, u128), + (u128, u128), (u128, u128), + (u128, u128), (u128, u128), + (u128, u128), (u128, u128), +) { + ( + diff(18, 1), + diff(1, 18), + diff(0, 170141183460469231731687303715884105727), + diff(170141183460469231731687303715884105727, 0), + diff(-18, 1), + diff(1, -18), + diff(0, -170141183460469231731687303715884105727), + diff(-170141183460469231731687303715884105727, 0), + ) +} diff --git a/tests/cases/sint/is_zero.cairo b/tests/cases/sint/is_zero.cairo index 13b9b986f..ad669b926 100644 --- a/tests/cases/sint/is_zero.cairo +++ b/tests/cases/sint/is_zero.cairo @@ -28,11 +28,19 @@ fn is_zero_i64(val: i64) -> bool { } } +fn is_zero_i128(val: i128) -> bool { + match integer::i128_is_zero(val) { + IsZeroResult::Zero => true, + IsZeroResult::NonZero(_) => false, + } +} + fn main() -> ( bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, bool, + bool, bool, bool, ) { ( is_zero_i8(17), @@ -50,5 +58,9 @@ fn main() -> ( is_zero_i64(17), is_zero_i64(-17), is_zero_i64(0), + + is_zero_i128(17), + is_zero_i128(-17), + is_zero_i128(0), ) } diff --git a/tests/cases/sint/to_from_felt252.cairo b/tests/cases/sint/to_from_felt252.cairo index ad6af0a45..03b5e55ed 100644 --- a/tests/cases/sint/to_from_felt252.cairo +++ b/tests/cases/sint/to_from_felt252.cairo @@ -5,6 +5,7 @@ fn main() -> ( felt252, felt252, Option, Option, Option, felt252, felt252, Option, Option, Option, felt252, felt252, Option, Option, Option, + felt252, felt252, Option, Option, Option, ) { ( 17_i8.into(), @@ -30,5 +31,11 @@ fn main() -> ( 17.try_into(), 9223372036854775809.try_into(), 24857893469346978675645.try_into(), + + 17_i32.into(), + -17_i32.into(), + 17.try_into(), + 170141183460469231731687303715884105728.try_into(), + 2485789346934697867564578687675665453442.try_into(), ) }