From 7b36d84c85c2177b788f7fa4f953dc20f07b9164 Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Fri, 14 Nov 2025 16:28:07 -0300 Subject: [PATCH 01/13] add some tests on bounded_int_mul --- src/libfuncs/bounded_int.rs | 178 +++++++++++++++++++++++++++++++----- 1 file changed, 153 insertions(+), 25 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 35cf19c7b..f57a265e2 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -851,44 +851,172 @@ fn build_wrap_non_zero<'ctx, 'this>( #[cfg(test)] mod test { + use cairo_lang_sierra::extensions::utils::Range; use cairo_vm::Felt252; + use num_bigint::BigInt; use crate::{ context::NativeContext, execution_result::ExecutionResult, executor::JitNativeExecutor, - load_cairo, OptLevel, Value, + jit_enum, jit_struct, load_cairo, utils::testing::run_program_assert_output, OptLevel, + Value, }; #[test] - fn test_trim_some_pos_i8() { - let (_, program) = load_cairo!( + fn test_bounded_int_mul() { + let cairo = load_cairo!( #[feature("bounded-int-utils")] - use core::internal::bounded_int::{self, BoundedInt}; - use core::internal::OptionRev; + use core::internal::bounded_int::{self, BoundedInt, MulHelper, mul}; - fn main() -> BoundedInt<-128, 126> { - let num = match bounded_int::trim_max::(1) { - OptionRev::Some(n) => n, - OptionRev::None => 0, - }; + impl MulHelper1 of MulHelper, BoundedInt<-128, 127>> { + type Result = BoundedInt<-16256, 16384>; + } - num + impl MulHelper2 of MulHelper, BoundedInt<0, 128>> { + type Result = BoundedInt<0, 16384>; + } + + impl MulHelper3 of MulHelper, BoundedInt<1, 1>> { + type Result = BoundedInt<1, 31>; + } + + impl MulHelper4 of MulHelper, BoundedInt<-1, -1>> { + type Result = BoundedInt<-31, 1>; + } + + impl MulHelper5 of MulHelper, BoundedInt<1, 1>> { + type Result = BoundedInt<31, 31>; + } + + fn run_test_1(a: felt252, b: felt252) -> BoundedInt<-16256, 16384> { + let a: BoundedInt<-128, 127> = a.try_into().unwrap(); + let b: BoundedInt<-128, 127> = b.try_into().unwrap(); + + mul(a,b) + } + + fn run_test_2(a: felt252, b: felt252) -> BoundedInt<0, 16384> { + let a: BoundedInt<0, 128> = a.try_into().unwrap(); + let b: BoundedInt<0, 128> = b.try_into().unwrap(); + + mul(a,b) + } + + fn run_test_3(a: felt252, b: felt252) -> BoundedInt<31, 31> { + let a: BoundedInt<31, 31> = a.try_into().unwrap(); + let b: BoundedInt<1, 1> = b.try_into().unwrap(); + + mul(a,b) + } + + fn run_test_4(a: felt252, b: felt252) -> BoundedInt<-31, 1> { + let a: BoundedInt<-1, 31> = a.try_into().unwrap(); + let b: BoundedInt<-1, -1> = b.try_into().unwrap(); + + mul(a,b) + } + + fn run_test_5(a: felt252, b: felt252) -> BoundedInt<31, 31> { + let a: BoundedInt<31, 31> = a.try_into().unwrap(); + let b: BoundedInt<1, 1> = b.try_into().unwrap(); + + mul(a,b) } ); - let ctx = NativeContext::new(); - let module = ctx.compile(&program, false, None, None).unwrap(); - let executor = JitNativeExecutor::from_native_module(module, OptLevel::Default).unwrap(); - let ExecutionResult { - remaining_gas: _, - return_value, - builtin_stats: _, - } = executor - .invoke_dynamic(&program.funcs[0].id, &[], None) - .unwrap(); - let Value::BoundedInt { value, range: _ } = return_value else { - panic!(); - }; - assert_eq!(value, Felt252::from(1_u8)); + run_program_assert_output( + &cairo, + "run_test_1", + &[ + Value::Felt252(Felt252::from(-128)), + Value::Felt252(Felt252::from(-128)), + ], + jit_enum!( + 0, + jit_struct!(Value::BoundedInt { + value: Felt252::from(16384), + range: Range { + lower: BigInt::from(-16256), + upper: BigInt::from(16385), + } + }) + ), + ); + + run_program_assert_output( + &cairo, + "run_test_2", + &[ + Value::Felt252(Felt252::from(126)), + Value::Felt252(Felt252::from(128)), + ], + jit_enum!( + 0, + jit_struct!(Value::BoundedInt { + value: Felt252::from(16128), + range: Range { + lower: BigInt::from(0), + upper: BigInt::from(16385), + } + }) + ), + ); + + run_program_assert_output( + &cairo, + "run_test_3", + &[ + Value::Felt252(Felt252::from(31)), + Value::Felt252(Felt252::from(1)), + ], + jit_enum!( + 0, + jit_struct!(Value::BoundedInt { + value: Felt252::from(31), + range: Range { + lower: BigInt::from(1), + upper: BigInt::from(32), + } + }) + ), + ); + + run_program_assert_output( + &cairo, + "run_test_4", + &[ + Value::Felt252(Felt252::from(31)), + Value::Felt252(Felt252::from(-1)), + ], + jit_enum!( + 0, + jit_struct!(Value::BoundedInt { + value: Felt252::from(-31), + range: Range { + lower: BigInt::from(-31), + upper: BigInt::from(2), + } + }) + ), + ); + + run_program_assert_output( + &cairo, + "run_test_5", + &[ + Value::Felt252(Felt252::from(31)), + Value::Felt252(Felt252::from(1)), + ], + jit_enum!( + 0, + jit_struct!(Value::BoundedInt { + value: Felt252::from(31), + range: Range { + lower: BigInt::from(31), + upper: BigInt::from(32), + } + }) + ), + ); } #[test] From 3716ff25b0c896d5fc4d6e8a92664fbeb41ed8ef Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Mon, 17 Nov 2025 09:11:37 -0300 Subject: [PATCH 02/13] add more tests on bounded_int_mul --- src/libfuncs/bounded_int.rs | 38 +++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index f57a265e2..97c80b20d 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -887,6 +887,14 @@ mod test { type Result = BoundedInt<31, 31>; } + impl MulHelper6 of MulHelper, BoundedInt<0, 100>> { + type Result = BoundedInt<-10000, 0>; + } + + impl MulHelper6 of MulHelper, BoundedInt<1, 1>> { + type Result = BoundedInt<1, 1>; + } + fn run_test_1(a: felt252, b: felt252) -> BoundedInt<-16256, 16384> { let a: BoundedInt<-128, 127> = a.try_into().unwrap(); let b: BoundedInt<-128, 127> = b.try_into().unwrap(); @@ -901,8 +909,8 @@ mod test { mul(a,b) } - fn run_test_3(a: felt252, b: felt252) -> BoundedInt<31, 31> { - let a: BoundedInt<31, 31> = a.try_into().unwrap(); + fn run_test_3(a: felt252, b: felt252) -> BoundedInt<1, 31> { + let a: BoundedInt<1, 31> = a.try_into().unwrap(); let b: BoundedInt<1, 1> = b.try_into().unwrap(); mul(a,b) @@ -921,6 +929,13 @@ mod test { mul(a,b) } + + fn run_test_6(a: felt252, b: felt252) -> BoundedInt<-10000,0> { + let a: BoundedInt<-100, 0> = a.try_into().unwrap(); + let b: BoundedInt<0, 100> = b.try_into().unwrap(); + + mul(a,b) + } ); run_program_assert_output( @@ -1017,6 +1032,25 @@ mod test { }) ), ); + + run_program_assert_output( + &cairo, + "run_test_6", + &[ + Value::Felt252(Felt252::from(-100)), + Value::Felt252(Felt252::from(100)), + ], + jit_enum!( + 0, + jit_struct!(Value::BoundedInt { + value: Felt252::from(-10000), + range: Range { + lower: BigInt::from(-10000), + upper: BigInt::from(1), + } + }) + ), + ); } #[test] From 258da413c0b9ee02dc9348a4a3e5465fa275297c Mon Sep 17 00:00:00 2001 From: FrancoGiachetta Date: Tue, 18 Nov 2025 12:16:49 -0300 Subject: [PATCH 03/13] add test removed --- src/libfuncs/bounded_int.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 97c80b20d..89b406173 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -1053,6 +1053,39 @@ mod test { ); } + #[test] + fn test_trim_some_pos_i8() { + let (_, program) = load_cairo!( + #[feature("bounded-int-utils")] + use core::internal::bounded_int::{self, BoundedInt}; + use core::internal::OptionRev; + + fn main() -> BoundedInt<-128, 126> { + let num = match bounded_int::trim_max::(1) { + OptionRev::Some(n) => n, + OptionRev::None => 0, + }; + + num + } + ); + let ctx = NativeContext::new(); + let module = ctx.compile(&program, false, None, None).unwrap(); + let executor = JitNativeExecutor::from_native_module(module, OptLevel::Default).unwrap(); + let ExecutionResult { + remaining_gas: _, + return_value, + builtin_stats: _, + } = executor + .invoke_dynamic(&program.funcs[0].id, &[], None) + .unwrap(); + + let Value::BoundedInt { value, range: _ } = return_value else { + panic!(); + }; + assert_eq!(value, Felt252::from(1_u8)); + } + #[test] fn test_trim_some_neg_i8() { let (_, program) = load_cairo!( From 3875f52d2005bb743a20eaa09ec742041db005f9 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Tue, 25 Nov 2025 18:25:47 -0300 Subject: [PATCH 04/13] Begin new implementation of mul --- src/libfuncs/bounded_int.rs | 103 +++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 89b406173..44ce9cafe 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -340,7 +340,7 @@ fn build_mul<'ctx, 'this>( let lhs_value = entry.arg(0)?; let rhs_value = entry.arg(1)?; - // Extract the ranges for the operands and the result type. + // Extract the ranges for the operands. let lhs_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; let rhs_ty = registry.get_type(&info.signature.param_signatures[1].ty)?; @@ -351,41 +351,57 @@ fn build_mul<'ctx, 'this>( .integer_range(registry)?; let lhs_width = if lhs_ty.is_bounded_int(registry)? { + // P lhs_range.offset_bit_width() } else { lhs_range.zero_based_bit_width() }; let rhs_width = if rhs_ty.is_bounded_int(registry)? { + // Q rhs_range.offset_bit_width() } else { rhs_range.zero_based_bit_width() }; + let lhs_lower_width = if lhs_range.lower.sign() != Sign::Minus { + // R + lhs_range.lower.bits() + } else { + lhs_range.lower.bits() + 1 // TODO: Check if this is correct + }; + let rhs_lower_width = if rhs_range.lower.sign() != Sign::Minus { + // S + rhs_range.lower.bits() + } else { + rhs_range.lower.bits() + 1 // TODO: Check if this is correct + }; - // Calculate the computation range. - let compute_range = Range { - lower: (&lhs_range.lower) - .min(&rhs_range.lower) - .min(&dst_range.lower) - .min(&BigInt::ZERO) - .clone(), - upper: (&lhs_range.upper) - .max(&rhs_range.upper) - .max(&dst_range.upper) - .clone(), + let compile_time_val = + lhs_range.lower.clone() * rhs_range.lower.clone() - dst_range.lower.clone(); + let w = if compile_time_val.sign() != Sign::Minus { + // W + compile_time_val.bits() + } else { + compile_time_val.bits() + 1 // TODO: Check if this is correct }; - let compute_ty = IntegerType::new(context, compute_range.zero_based_bit_width()).into(); + + let x = (lhs_width.max(rhs_width) * 2) as u64; + let y = lhs_lower_width.max(rhs_lower_width) * 2; + let z = (rhs_width as u64).max(lhs_lower_width) * 2; + + let compute_width = (x.max(y).max(z).max(w) + 3) as u32; + let compute_ty = IntegerType::new(context, compute_width).into(); // Zero-extend operands into the computation range. native_assert!( - compute_range.offset_bit_width() >= lhs_width, + compute_width >= lhs_width, "the lhs_range bit_width must be less or equal than the compute_range" ); native_assert!( - compute_range.offset_bit_width() >= rhs_width, + compute_width >= rhs_width, "the rhs_range bit_width must be less or equal than the compute_range" ); - let lhs_value = if compute_range.zero_based_bit_width() > lhs_width { + let lhs_value = if compute_width > lhs_width { if lhs_range.lower.sign() != Sign::Minus || lhs_ty.is_bounded_int(registry)? { entry.extui(lhs_value, compute_ty, location)? } else { @@ -394,7 +410,7 @@ fn build_mul<'ctx, 'this>( } else { lhs_value }; - let rhs_value = if compute_range.zero_based_bit_width() > rhs_width { + let rhs_value = if compute_width > rhs_width { if rhs_range.lower.sign() != Sign::Minus || rhs_ty.is_bounded_int(registry)? { entry.extui(rhs_value, compute_ty, location)? } else { @@ -404,43 +420,32 @@ fn build_mul<'ctx, 'this>( rhs_value }; - // Offset the operands so that they are compatible with the operation. - let lhs_value = if lhs_ty.is_bounded_int(registry)? && lhs_range.lower != BigInt::ZERO { - let lhs_offset = - entry.const_int_from_type(context, location, lhs_range.lower, compute_ty)?; - entry.addi(lhs_value, lhs_offset, location)? - } else { - lhs_value - }; - let rhs_value = if rhs_ty.is_bounded_int(registry)? && rhs_range.lower != BigInt::ZERO { - let rhs_offset = - entry.const_int_from_type(context, location, rhs_range.lower, compute_ty)?; - entry.addi(rhs_value, rhs_offset, location)? - } else { - rhs_value - }; + let ao = entry.const_int_from_type(context, location, lhs_range.lower, compute_ty)?; + let bo = entry.const_int_from_type(context, location, rhs_range.lower, compute_ty)?; - // Compute the operation. - let res_value = entry.muli(lhs_value, rhs_value, location)?; + let ad_bd = entry.muli(lhs_value, rhs_value, location)?; + let ad_bo = entry.muli(lhs_value, bo, location)?; + let bd_ao = entry.muli(rhs_value, ao, location)?; + let compile_time_val = + entry.const_int_from_type(context, location, compile_time_val, compute_ty)?; - // Offset and truncate the result to the output type. - let res_offset = (&dst_range.lower).max(&compute_range.lower).clone(); - let res_value = if res_offset != BigInt::ZERO { - let res_offset = entry.const_int_from_type(context, location, res_offset, compute_ty)?; - entry.append_op_result(arith::subi(res_value, res_offset, location))? - } else { - res_value - }; + let res_value = entry.addi(ad_bd, ad_bo, location)?; + let res_value = entry.addi(res_value, bd_ao, location)?; + let mut res_value = entry.addi(res_value, compile_time_val, location)?; - let res_value = if dst_range.offset_bit_width() < compute_range.zero_based_bit_width() { - entry.trunci( + if compute_width > dst_range.offset_bit_width() { + res_value = entry.trunci( res_value, IntegerType::new(context, dst_range.offset_bit_width()).into(), location, )? - } else { - res_value - }; + } else if compute_width < dst_range.offset_bit_width() { + res_value = entry.extui( + res_value, + IntegerType::new(context, dst_range.offset_bit_width()).into(), + location, + )? + } helper.br(entry, 0, &[res_value], location) } @@ -862,7 +867,7 @@ mod test { }; #[test] - fn test_bounded_int_mul() { + fn test_mul() { let cairo = load_cairo!( #[feature("bounded-int-utils")] use core::internal::bounded_int::{self, BoundedInt, MulHelper, mul}; @@ -891,7 +896,7 @@ mod test { type Result = BoundedInt<-10000, 0>; } - impl MulHelper6 of MulHelper, BoundedInt<1, 1>> { + impl MulHelper7 of MulHelper, BoundedInt<1, 1>> { type Result = BoundedInt<1, 1>; } From c0194df4a1599a42858ba59a0ef0ead4e6a954f0 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Wed, 26 Nov 2025 10:21:52 -0300 Subject: [PATCH 05/13] Add comments and docu --- src/libfuncs/bounded_int.rs | 80 +++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 44ce9cafe..dc838d458 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -327,6 +327,27 @@ fn build_sub<'ctx, 'this>( } /// Generate MLIR operations for the `bounded_int_mul` libfunc. +/// +/// Since we want to get `C = A * B`, we can translate this to +/// `Co + Cd = (Ad + Ao) * (Bd + Bo)`. Where `Ao`, `Bo` and `Co` represent the lower bound +/// of the ranges in the BoundedInt and `Ad`, `Bd` and `Cd` represent the offsets. +/// +/// We want `Cd = (Ad * Bd) + (Ad * Bo) + (Bd * Ao) + (Ao * Bo - Co)` +/// +/// We can separate it into run-time values: +/// - `Ad` with `P` bits. +/// - `Bd` with `Q` bits. +/// - `Ad * Bd` with `X = max(P, Q) * 2` bits +/// - `Ad * Bo` with `Y = max(P, S) * 2` bits +/// - `Bd * Ao` with `Z = max(Q, R) * 2` bits +/// +/// And compile-time values: +/// - `Ao` with `R` bits. +/// - `Bo` with `S` bits. +/// - `Ao * Bo - Co` with `W` bits. +/// +/// To compute the `Cd` we will have intermediate values that will need at least +/// `max(X,Y,Z,W) + 3` bits. #[allow(clippy::too_many_arguments)] fn build_mul<'ctx, 'this>( context: &'ctx Context, @@ -350,58 +371,55 @@ fn build_mul<'ctx, 'this>( .get_type(&info.signature.branch_signatures[0].vars[0].ty)? .integer_range(registry)?; - let lhs_width = if lhs_ty.is_bounded_int(registry)? { - // P + // Get all the widths so we can get the compute width we need + let p_width = if lhs_ty.is_bounded_int(registry)? { lhs_range.offset_bit_width() } else { lhs_range.zero_based_bit_width() }; - let rhs_width = if rhs_ty.is_bounded_int(registry)? { - // Q + let q_width = if rhs_ty.is_bounded_int(registry)? { rhs_range.offset_bit_width() } else { rhs_range.zero_based_bit_width() }; - let lhs_lower_width = if lhs_range.lower.sign() != Sign::Minus { - // R + let r_width = if lhs_range.lower.sign() != Sign::Minus { lhs_range.lower.bits() } else { - lhs_range.lower.bits() + 1 // TODO: Check if this is correct + lhs_range.lower.bits() + 1 }; - let rhs_lower_width = if rhs_range.lower.sign() != Sign::Minus { - // S + let s_width = if rhs_range.lower.sign() != Sign::Minus { rhs_range.lower.bits() } else { - rhs_range.lower.bits() + 1 // TODO: Check if this is correct + rhs_range.lower.bits() + 1 }; let compile_time_val = lhs_range.lower.clone() * rhs_range.lower.clone() - dst_range.lower.clone(); - let w = if compile_time_val.sign() != Sign::Minus { - // W + let w_width = if compile_time_val.sign() != Sign::Minus { compile_time_val.bits() } else { - compile_time_val.bits() + 1 // TODO: Check if this is correct + compile_time_val.bits() + 1 }; - let x = (lhs_width.max(rhs_width) * 2) as u64; - let y = lhs_lower_width.max(rhs_lower_width) * 2; - let z = (rhs_width as u64).max(lhs_lower_width) * 2; + let x = (p_width.max(q_width) * 2) as u64; + let y = r_width.max(s_width) * 2; + let z = (q_width as u64).max(r_width) * 2; - let compute_width = (x.max(y).max(z).max(w) + 3) as u32; + // Get the compute width + let compute_width = (x.max(y).max(z).max(w_width) + 3) as u32; let compute_ty = IntegerType::new(context, compute_width).into(); - // Zero-extend operands into the computation range. native_assert!( - compute_width >= lhs_width, + compute_width >= p_width, "the lhs_range bit_width must be less or equal than the compute_range" ); native_assert!( - compute_width >= rhs_width, + compute_width >= q_width, "the rhs_range bit_width must be less or equal than the compute_range" ); - let lhs_value = if compute_width > lhs_width { + // Extend the operands to the compute width if necessary + let lhs_value = if compute_width > p_width { if lhs_range.lower.sign() != Sign::Minus || lhs_ty.is_bounded_int(registry)? { entry.extui(lhs_value, compute_ty, location)? } else { @@ -410,7 +428,7 @@ fn build_mul<'ctx, 'this>( } else { lhs_value }; - let rhs_value = if compute_width > rhs_width { + let rhs_value = if compute_width > q_width { if rhs_range.lower.sign() != Sign::Minus || rhs_ty.is_bounded_int(registry)? { entry.extui(rhs_value, compute_ty, location)? } else { @@ -420,19 +438,23 @@ fn build_mul<'ctx, 'this>( rhs_value }; + // Get the necessary values let ao = entry.const_int_from_type(context, location, lhs_range.lower, compute_ty)?; let bo = entry.const_int_from_type(context, location, rhs_range.lower, compute_ty)?; - - let ad_bd = entry.muli(lhs_value, rhs_value, location)?; - let ad_bo = entry.muli(lhs_value, bo, location)?; - let bd_ao = entry.muli(rhs_value, ao, location)?; let compile_time_val = entry.const_int_from_type(context, location, compile_time_val, compute_ty)?; - let res_value = entry.addi(ad_bd, ad_bo, location)?; - let res_value = entry.addi(res_value, bd_ao, location)?; - let mut res_value = entry.addi(res_value, compile_time_val, location)?; + // Calculate the different terms of the equation + let ad_bd = entry.muli(lhs_value, rhs_value, location)?; // Ad * Bd + let ad_bo = entry.muli(lhs_value, bo, location)?; // Ad * Bo + let bd_ao = entry.muli(rhs_value, ao, location)?; // Bd * Ao + + // Calculate the result + let res_value = entry.addi(ad_bd, ad_bo, location)?; // (Ad * Bd) + (Ad * Bo) + let res_value = entry.addi(res_value, bd_ao, location)?; // (Ad * Bd) + (Ad * Bo) + (Bd * Ao) + let mut res_value = entry.addi(res_value, compile_time_val, location)?; // (Ad * Bd) + (Ad * Bo) + (Bd * Ao) + (Ao * Bo - Co) + // Get the result value on the desired range if compute_width > dst_range.offset_bit_width() { res_value = entry.trunci( res_value, From cf4ba418860759a09cb9bd643388fea44b21f958 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Wed, 26 Nov 2025 10:28:13 -0300 Subject: [PATCH 06/13] Add test case --- src/libfuncs/bounded_int.rs | 60 +++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index dc838d458..de127cbfb 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -892,7 +892,7 @@ mod test { fn test_mul() { let cairo = load_cairo!( #[feature("bounded-int-utils")] - use core::internal::bounded_int::{self, BoundedInt, MulHelper, mul}; + use core::internal::bounded_int::{self, BoundedInt, MulHelper, mul, UnitInt}; impl MulHelper1 of MulHelper, BoundedInt<-128, 127>> { type Result = BoundedInt<-16256, 16384>; @@ -922,6 +922,10 @@ mod test { type Result = BoundedInt<1, 1>; } + impl MulHelper8 of MulHelper, UnitInt<2>> { + type Result = BoundedInt<-10, 10>; + } + fn run_test_1(a: felt252, b: felt252) -> BoundedInt<-16256, 16384> { let a: BoundedInt<-128, 127> = a.try_into().unwrap(); let b: BoundedInt<-128, 127> = b.try_into().unwrap(); @@ -957,12 +961,26 @@ mod test { mul(a,b) } - fn run_test_6(a: felt252, b: felt252) -> BoundedInt<-10000,0> { + fn run_test_6(a: felt252, b: felt252) -> BoundedInt<-10000, 0> { let a: BoundedInt<-100, 0> = a.try_into().unwrap(); let b: BoundedInt<0, 100> = b.try_into().unwrap(); mul(a,b) } + + fn run_test_7(a: felt252, b: felt252) -> BoundedInt<1, 1> { + let a: BoundedInt<1, 1> = a.try_into().unwrap(); + let b: BoundedInt<1, 1> = b.try_into().unwrap(); + + mul(a,b) + } + + fn run_test_8(a: felt252, b: felt252) -> BoundedInt<-10, 10> { + let a: BoundedInt<-5, 5> = a.try_into().unwrap(); + let b: UnitInt<2> = b.try_into().unwrap(); + + mul(a,b) + } ); run_program_assert_output( @@ -1078,6 +1096,44 @@ mod test { }) ), ); + + run_program_assert_output( + &cairo, + "run_test_7", + &[ + Value::Felt252(Felt252::from(1)), + Value::Felt252(Felt252::from(1)), + ], + jit_enum!( + 0, + jit_struct!(Value::BoundedInt { + value: Felt252::from(1), + range: Range { + lower: BigInt::from(1), + upper: BigInt::from(2), + } + }) + ), + ); + + run_program_assert_output( + &cairo, + "run_test_8", + &[ + Value::Felt252(Felt252::from(-3)), + Value::Felt252(Felt252::from(2)), + ], + jit_enum!( + 0, + jit_struct!(Value::BoundedInt { + value: Felt252::from(-6), + range: Range { + lower: BigInt::from(-10), + upper: BigInt::from(11), + } + }) + ), + ); } #[test] From 3258c5709481c00e92591e348de0f6045083e348 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Wed, 26 Nov 2025 15:32:08 -0300 Subject: [PATCH 07/13] Revert "Add comments and docu" This reverts commit c0194df4a1599a42858ba59a0ef0ead4e6a954f0. --- src/libfuncs/bounded_int.rs | 80 ++++++++++++++----------------------- 1 file changed, 29 insertions(+), 51 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index e26a02303..5fd1c2a8d 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -327,27 +327,6 @@ fn build_sub<'ctx, 'this>( } /// Generate MLIR operations for the `bounded_int_mul` libfunc. -/// -/// Since we want to get `C = A * B`, we can translate this to -/// `Co + Cd = (Ad + Ao) * (Bd + Bo)`. Where `Ao`, `Bo` and `Co` represent the lower bound -/// of the ranges in the BoundedInt and `Ad`, `Bd` and `Cd` represent the offsets. -/// -/// We want `Cd = (Ad * Bd) + (Ad * Bo) + (Bd * Ao) + (Ao * Bo - Co)` -/// -/// We can separate it into run-time values: -/// - `Ad` with `P` bits. -/// - `Bd` with `Q` bits. -/// - `Ad * Bd` with `X = max(P, Q) * 2` bits -/// - `Ad * Bo` with `Y = max(P, S) * 2` bits -/// - `Bd * Ao` with `Z = max(Q, R) * 2` bits -/// -/// And compile-time values: -/// - `Ao` with `R` bits. -/// - `Bo` with `S` bits. -/// - `Ao * Bo - Co` with `W` bits. -/// -/// To compute the `Cd` we will have intermediate values that will need at least -/// `max(X,Y,Z,W) + 3` bits. #[allow(clippy::too_many_arguments)] fn build_mul<'ctx, 'this>( context: &'ctx Context, @@ -371,55 +350,58 @@ fn build_mul<'ctx, 'this>( .get_type(&info.signature.branch_signatures[0].vars[0].ty)? .integer_range(registry)?; - // Get all the widths so we can get the compute width we need - let p_width = if lhs_ty.is_bounded_int(registry)? { + let lhs_width = if lhs_ty.is_bounded_int(registry)? { + // P lhs_range.offset_bit_width() } else { lhs_range.zero_based_bit_width() }; - let q_width = if rhs_ty.is_bounded_int(registry)? { + let rhs_width = if rhs_ty.is_bounded_int(registry)? { + // Q rhs_range.offset_bit_width() } else { rhs_range.zero_based_bit_width() }; - let r_width = if lhs_range.lower.sign() != Sign::Minus { + let lhs_lower_width = if lhs_range.lower.sign() != Sign::Minus { + // R lhs_range.lower.bits() } else { - lhs_range.lower.bits() + 1 + lhs_range.lower.bits() + 1 // TODO: Check if this is correct }; - let s_width = if rhs_range.lower.sign() != Sign::Minus { + let rhs_lower_width = if rhs_range.lower.sign() != Sign::Minus { + // S rhs_range.lower.bits() } else { - rhs_range.lower.bits() + 1 + rhs_range.lower.bits() + 1 // TODO: Check if this is correct }; let compile_time_val = lhs_range.lower.clone() * rhs_range.lower.clone() - dst_range.lower.clone(); - let w_width = if compile_time_val.sign() != Sign::Minus { + let w = if compile_time_val.sign() != Sign::Minus { + // W compile_time_val.bits() } else { - compile_time_val.bits() + 1 + compile_time_val.bits() + 1 // TODO: Check if this is correct }; - let x = (p_width.max(q_width) * 2) as u64; - let y = r_width.max(s_width) * 2; - let z = (q_width as u64).max(r_width) * 2; + let x = (lhs_width.max(rhs_width) * 2) as u64; + let y = lhs_lower_width.max(rhs_lower_width) * 2; + let z = (rhs_width as u64).max(lhs_lower_width) * 2; - // Get the compute width - let compute_width = (x.max(y).max(z).max(w_width) + 3) as u32; + let compute_width = (x.max(y).max(z).max(w) + 3) as u32; let compute_ty = IntegerType::new(context, compute_width).into(); + // Zero-extend operands into the computation range. native_assert!( - compute_width >= p_width, + compute_width >= lhs_width, "the lhs_range bit_width must be less or equal than the compute_range" ); native_assert!( - compute_width >= q_width, + compute_width >= rhs_width, "the rhs_range bit_width must be less or equal than the compute_range" ); - // Extend the operands to the compute width if necessary - let lhs_value = if compute_width > p_width { + let lhs_value = if compute_width > lhs_width { if lhs_range.lower.sign() != Sign::Minus || lhs_ty.is_bounded_int(registry)? { entry.extui(lhs_value, compute_ty, location)? } else { @@ -428,7 +410,7 @@ fn build_mul<'ctx, 'this>( } else { lhs_value }; - let rhs_value = if compute_width > q_width { + let rhs_value = if compute_width > rhs_width { if rhs_range.lower.sign() != Sign::Minus || rhs_ty.is_bounded_int(registry)? { entry.extui(rhs_value, compute_ty, location)? } else { @@ -438,23 +420,19 @@ fn build_mul<'ctx, 'this>( rhs_value }; - // Get the necessary values let ao = entry.const_int_from_type(context, location, lhs_range.lower, compute_ty)?; let bo = entry.const_int_from_type(context, location, rhs_range.lower, compute_ty)?; + + let ad_bd = entry.muli(lhs_value, rhs_value, location)?; + let ad_bo = entry.muli(lhs_value, bo, location)?; + let bd_ao = entry.muli(rhs_value, ao, location)?; let compile_time_val = entry.const_int_from_type(context, location, compile_time_val, compute_ty)?; - // Calculate the different terms of the equation - let ad_bd = entry.muli(lhs_value, rhs_value, location)?; // Ad * Bd - let ad_bo = entry.muli(lhs_value, bo, location)?; // Ad * Bo - let bd_ao = entry.muli(rhs_value, ao, location)?; // Bd * Ao - - // Calculate the result - let res_value = entry.addi(ad_bd, ad_bo, location)?; // (Ad * Bd) + (Ad * Bo) - let res_value = entry.addi(res_value, bd_ao, location)?; // (Ad * Bd) + (Ad * Bo) + (Bd * Ao) - let mut res_value = entry.addi(res_value, compile_time_val, location)?; // (Ad * Bd) + (Ad * Bo) + (Bd * Ao) + (Ao * Bo - Co) + let res_value = entry.addi(ad_bd, ad_bo, location)?; + let res_value = entry.addi(res_value, bd_ao, location)?; + let mut res_value = entry.addi(res_value, compile_time_val, location)?; - // Get the result value on the desired range if compute_width > dst_range.offset_bit_width() { res_value = entry.trunci( res_value, From bb87efa0e1dec22b890bbd469f346f0d17ece561 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Wed, 26 Nov 2025 15:32:13 -0300 Subject: [PATCH 08/13] Revert "Begin new implementation of mul" This reverts commit 3875f52d2005bb743a20eaa09ec742041db005f9. --- src/libfuncs/bounded_int.rs | 103 +++++++++++++++++------------------- 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 5fd1c2a8d..8de28182d 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -340,7 +340,7 @@ fn build_mul<'ctx, 'this>( let lhs_value = entry.arg(0)?; let rhs_value = entry.arg(1)?; - // Extract the ranges for the operands. + // Extract the ranges for the operands and the result type. let lhs_ty = registry.get_type(&info.signature.param_signatures[0].ty)?; let rhs_ty = registry.get_type(&info.signature.param_signatures[1].ty)?; @@ -351,57 +351,41 @@ fn build_mul<'ctx, 'this>( .integer_range(registry)?; let lhs_width = if lhs_ty.is_bounded_int(registry)? { - // P lhs_range.offset_bit_width() } else { lhs_range.zero_based_bit_width() }; let rhs_width = if rhs_ty.is_bounded_int(registry)? { - // Q rhs_range.offset_bit_width() } else { rhs_range.zero_based_bit_width() }; - let lhs_lower_width = if lhs_range.lower.sign() != Sign::Minus { - // R - lhs_range.lower.bits() - } else { - lhs_range.lower.bits() + 1 // TODO: Check if this is correct - }; - let rhs_lower_width = if rhs_range.lower.sign() != Sign::Minus { - // S - rhs_range.lower.bits() - } else { - rhs_range.lower.bits() + 1 // TODO: Check if this is correct - }; - let compile_time_val = - lhs_range.lower.clone() * rhs_range.lower.clone() - dst_range.lower.clone(); - let w = if compile_time_val.sign() != Sign::Minus { - // W - compile_time_val.bits() - } else { - compile_time_val.bits() + 1 // TODO: Check if this is correct + // Calculate the computation range. + let compute_range = Range { + lower: (&lhs_range.lower) + .min(&rhs_range.lower) + .min(&dst_range.lower) + .min(&BigInt::ZERO) + .clone(), + upper: (&lhs_range.upper) + .max(&rhs_range.upper) + .max(&dst_range.upper) + .clone(), }; - - let x = (lhs_width.max(rhs_width) * 2) as u64; - let y = lhs_lower_width.max(rhs_lower_width) * 2; - let z = (rhs_width as u64).max(lhs_lower_width) * 2; - - let compute_width = (x.max(y).max(z).max(w) + 3) as u32; - let compute_ty = IntegerType::new(context, compute_width).into(); + let compute_ty = IntegerType::new(context, compute_range.zero_based_bit_width()).into(); // Zero-extend operands into the computation range. native_assert!( - compute_width >= lhs_width, + compute_range.offset_bit_width() >= lhs_width, "the lhs_range bit_width must be less or equal than the compute_range" ); native_assert!( - compute_width >= rhs_width, + compute_range.offset_bit_width() >= rhs_width, "the rhs_range bit_width must be less or equal than the compute_range" ); - let lhs_value = if compute_width > lhs_width { + let lhs_value = if compute_range.zero_based_bit_width() > lhs_width { if lhs_range.lower.sign() != Sign::Minus || lhs_ty.is_bounded_int(registry)? { entry.extui(lhs_value, compute_ty, location)? } else { @@ -410,7 +394,7 @@ fn build_mul<'ctx, 'this>( } else { lhs_value }; - let rhs_value = if compute_width > rhs_width { + let rhs_value = if compute_range.zero_based_bit_width() > rhs_width { if rhs_range.lower.sign() != Sign::Minus || rhs_ty.is_bounded_int(registry)? { entry.extui(rhs_value, compute_ty, location)? } else { @@ -420,32 +404,43 @@ fn build_mul<'ctx, 'this>( rhs_value }; - let ao = entry.const_int_from_type(context, location, lhs_range.lower, compute_ty)?; - let bo = entry.const_int_from_type(context, location, rhs_range.lower, compute_ty)?; + // Offset the operands so that they are compatible with the operation. + let lhs_value = if lhs_ty.is_bounded_int(registry)? && lhs_range.lower != BigInt::ZERO { + let lhs_offset = + entry.const_int_from_type(context, location, lhs_range.lower, compute_ty)?; + entry.addi(lhs_value, lhs_offset, location)? + } else { + lhs_value + }; + let rhs_value = if rhs_ty.is_bounded_int(registry)? && rhs_range.lower != BigInt::ZERO { + let rhs_offset = + entry.const_int_from_type(context, location, rhs_range.lower, compute_ty)?; + entry.addi(rhs_value, rhs_offset, location)? + } else { + rhs_value + }; - let ad_bd = entry.muli(lhs_value, rhs_value, location)?; - let ad_bo = entry.muli(lhs_value, bo, location)?; - let bd_ao = entry.muli(rhs_value, ao, location)?; - let compile_time_val = - entry.const_int_from_type(context, location, compile_time_val, compute_ty)?; + // Compute the operation. + let res_value = entry.muli(lhs_value, rhs_value, location)?; - let res_value = entry.addi(ad_bd, ad_bo, location)?; - let res_value = entry.addi(res_value, bd_ao, location)?; - let mut res_value = entry.addi(res_value, compile_time_val, location)?; + // Offset and truncate the result to the output type. + let res_offset = (&dst_range.lower).max(&compute_range.lower).clone(); + let res_value = if res_offset != BigInt::ZERO { + let res_offset = entry.const_int_from_type(context, location, res_offset, compute_ty)?; + entry.append_op_result(arith::subi(res_value, res_offset, location))? + } else { + res_value + }; - if compute_width > dst_range.offset_bit_width() { - res_value = entry.trunci( - res_value, - IntegerType::new(context, dst_range.offset_bit_width()).into(), - location, - )? - } else if compute_width < dst_range.offset_bit_width() { - res_value = entry.extui( + let res_value = if dst_range.offset_bit_width() < compute_range.zero_based_bit_width() { + entry.trunci( res_value, IntegerType::new(context, dst_range.offset_bit_width()).into(), location, )? - } + } else { + res_value + }; helper.br(entry, 0, &[res_value], location) } @@ -885,7 +880,7 @@ mod test { }; #[test] - fn test_mul() { + fn test_bounded_int_mul() { let cairo = load_cairo!( #[feature("bounded-int-utils")] use core::internal::bounded_int::{self, BoundedInt, MulHelper, mul, UnitInt}; @@ -914,7 +909,7 @@ mod test { type Result = BoundedInt<-10000, 0>; } - impl MulHelper7 of MulHelper, BoundedInt<1, 1>> { + impl MulHelper6 of MulHelper, BoundedInt<1, 1>> { type Result = BoundedInt<1, 1>; } From 54cee7aa09091b5c9ceb29ea3ce7879aab5c8a0c Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Wed, 26 Nov 2025 15:38:33 -0300 Subject: [PATCH 09/13] Refactor of res_offset calculation --- src/libfuncs/bounded_int.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 8de28182d..4ad48eb8e 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -424,7 +424,7 @@ fn build_mul<'ctx, 'this>( let res_value = entry.muli(lhs_value, rhs_value, location)?; // Offset and truncate the result to the output type. - let res_offset = (&dst_range.lower).max(&compute_range.lower).clone(); + let res_offset = dst_range.lower.clone(); let res_value = if res_offset != BigInt::ZERO { let res_offset = entry.const_int_from_type(context, location, res_offset, compute_ty)?; entry.append_op_result(arith::subi(res_value, res_offset, location))? @@ -880,7 +880,7 @@ mod test { }; #[test] - fn test_bounded_int_mul() { + fn test_mul() { let cairo = load_cairo!( #[feature("bounded-int-utils")] use core::internal::bounded_int::{self, BoundedInt, MulHelper, mul, UnitInt}; @@ -909,7 +909,7 @@ mod test { type Result = BoundedInt<-10000, 0>; } - impl MulHelper6 of MulHelper, BoundedInt<1, 1>> { + impl MulHelper7 of MulHelper, BoundedInt<1, 1>> { type Result = BoundedInt<1, 1>; } From 68908bcd5471eb6faa6e267d39931a636caaaa7e Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Thu, 27 Nov 2025 09:55:52 -0300 Subject: [PATCH 10/13] Refactor of tests --- src/libfuncs/bounded_int.rs | 177 +++++++----------------------------- 1 file changed, 31 insertions(+), 146 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 4ad48eb8e..da53594a9 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -866,9 +866,11 @@ fn build_wrap_non_zero<'ctx, 'this>( #[cfg(test)] mod test { - use cairo_lang_sierra::extensions::utils::Range; + use cairo_lang_sierra::{extensions::utils::Range, program::Program}; use cairo_vm::Felt252; + use lazy_static::lazy_static; use num_bigint::BigInt; + use test_case::test_case; use crate::{ context::NativeContext, @@ -879,10 +881,9 @@ mod test { OptLevel, Value, }; - #[test] - fn test_mul() { - let cairo = load_cairo!( - #[feature("bounded-int-utils")] + lazy_static! { + static ref TEST_MUL_PROGRAM: (String, Program) = load_cairo! { + #[feature("bounded-int-utils")] use core::internal::bounded_int::{self, BoundedInt, MulHelper, mul, UnitInt}; impl MulHelper1 of MulHelper, BoundedInt<-128, 127>> { @@ -972,155 +973,39 @@ mod test { mul(a,b) } - ); - - run_program_assert_output( - &cairo, - "run_test_1", - &[ - Value::Felt252(Felt252::from(-128)), - Value::Felt252(Felt252::from(-128)), - ], - jit_enum!( - 0, - jit_struct!(Value::BoundedInt { - value: Felt252::from(16384), - range: Range { - lower: BigInt::from(-16256), - upper: BigInt::from(16385), - } - }) - ), - ); - - run_program_assert_output( - &cairo, - "run_test_2", - &[ - Value::Felt252(Felt252::from(126)), - Value::Felt252(Felt252::from(128)), - ], - jit_enum!( - 0, - jit_struct!(Value::BoundedInt { - value: Felt252::from(16128), - range: Range { - lower: BigInt::from(0), - upper: BigInt::from(16385), - } - }) - ), - ); - - run_program_assert_output( - &cairo, - "run_test_3", - &[ - Value::Felt252(Felt252::from(31)), - Value::Felt252(Felt252::from(1)), - ], - jit_enum!( - 0, - jit_struct!(Value::BoundedInt { - value: Felt252::from(31), - range: Range { - lower: BigInt::from(1), - upper: BigInt::from(32), - } - }) - ), - ); - - run_program_assert_output( - &cairo, - "run_test_4", - &[ - Value::Felt252(Felt252::from(31)), - Value::Felt252(Felt252::from(-1)), - ], - jit_enum!( - 0, - jit_struct!(Value::BoundedInt { - value: Felt252::from(-31), - range: Range { - lower: BigInt::from(-31), - upper: BigInt::from(2), - } - }) - ), - ); - - run_program_assert_output( - &cairo, - "run_test_5", - &[ - Value::Felt252(Felt252::from(31)), - Value::Felt252(Felt252::from(1)), - ], - jit_enum!( - 0, - jit_struct!(Value::BoundedInt { - value: Felt252::from(31), - range: Range { - lower: BigInt::from(31), - upper: BigInt::from(32), - } - }) - ), - ); - - run_program_assert_output( - &cairo, - "run_test_6", - &[ - Value::Felt252(Felt252::from(-100)), - Value::Felt252(Felt252::from(100)), - ], - jit_enum!( - 0, - jit_struct!(Value::BoundedInt { - value: Felt252::from(-10000), - range: Range { - lower: BigInt::from(-10000), - upper: BigInt::from(1), - } - }) - ), - ); - - run_program_assert_output( - &cairo, - "run_test_7", - &[ - Value::Felt252(Felt252::from(1)), - Value::Felt252(Felt252::from(1)), - ], - jit_enum!( - 0, - jit_struct!(Value::BoundedInt { - value: Felt252::from(1), - range: Range { - lower: BigInt::from(1), - upper: BigInt::from(2), - } - }) - ), - ); + }; + } + #[test_case("run_test_1", -128, -128, 16384, -16256, 16385)] + #[test_case("run_test_2", 126, 128, 16128, 0, 16385)] + #[test_case("run_test_3", 31, 1, 31, 1, 32)] + #[test_case("run_test_4", 31, -1, -31, -31, 2)] + #[test_case("run_test_5", 31, 1, 31, 31, 32)] + #[test_case("run_test_6", -100, 100, -10000, -10000, 1)] + #[test_case("run_test_7", 1, 1, 1, 1, 2)] + #[test_case("run_test_8", -3, 2, -6, -10, 11)] + fn test_mul( + entry_point: &str, + lhs: i32, + rhs: i32, + result: i32, + lower_bound: i32, + upper_bound: i32, + ) { run_program_assert_output( - &cairo, - "run_test_8", + &TEST_MUL_PROGRAM, + entry_point, &[ - Value::Felt252(Felt252::from(-3)), - Value::Felt252(Felt252::from(2)), + Value::Felt252(Felt252::from(lhs)), + Value::Felt252(Felt252::from(rhs)), ], jit_enum!( 0, jit_struct!(Value::BoundedInt { - value: Felt252::from(-6), + value: Felt252::from(result), range: Range { - lower: BigInt::from(-10), - upper: BigInt::from(11), + lower: BigInt::from(lower_bound), + upper: BigInt::from(upper_bound), } }) ), From c7030635c0f4817388ed814996de7a1c41afe420 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Fri, 28 Nov 2025 12:27:29 -0300 Subject: [PATCH 11/13] Refactor of tests --- src/libfuncs/bounded_int.rs | 59 ++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index da53594a9..21ca34a05 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -873,12 +873,8 @@ mod test { use test_case::test_case; use crate::{ - context::NativeContext, - execution_result::ExecutionResult, - executor::JitNativeExecutor, - jit_enum, jit_struct, load_cairo, - utils::testing::{run_program, run_program_assert_output}, - OptLevel, Value, + context::NativeContext, execution_result::ExecutionResult, executor::JitNativeExecutor, + load_cairo, utils::testing::run_program, OptLevel, Value, }; lazy_static! { @@ -976,40 +972,35 @@ mod test { }; } - #[test_case("run_test_1", -128, -128, 16384, -16256, 16385)] - #[test_case("run_test_2", 126, 128, 16128, 0, 16385)] - #[test_case("run_test_3", 31, 1, 31, 1, 32)] - #[test_case("run_test_4", 31, -1, -31, -31, 2)] - #[test_case("run_test_5", 31, 1, 31, 31, 32)] - #[test_case("run_test_6", -100, 100, -10000, -10000, 1)] - #[test_case("run_test_7", 1, 1, 1, 1, 2)] - #[test_case("run_test_8", -3, 2, -6, -10, 11)] - fn test_mul( - entry_point: &str, - lhs: i32, - rhs: i32, - result: i32, - lower_bound: i32, - upper_bound: i32, - ) { - run_program_assert_output( + #[test_case("run_test_1", -128, -128, 16384)] + #[test_case("run_test_2", 126, 128, 16128)] + #[test_case("run_test_3", 31, 1, 31)] + #[test_case("run_test_4", 31, -1, -31)] + #[test_case("run_test_5", 31, 1, 31)] + #[test_case("run_test_6", -100, 100, -10000)] + #[test_case("run_test_7", 1, 1, 1)] + #[test_case("run_test_8", -3, 2, -6)] + fn test_mul(entry_point: &str, lhs: i32, rhs: i32, expected_result: i32) { + let result = run_program( &TEST_MUL_PROGRAM, entry_point, &[ Value::Felt252(Felt252::from(lhs)), Value::Felt252(Felt252::from(rhs)), ], - jit_enum!( - 0, - jit_struct!(Value::BoundedInt { - value: Felt252::from(result), - range: Range { - lower: BigInt::from(lower_bound), - upper: BigInt::from(upper_bound), - } - }) - ), - ); + ) + .return_value; + if let Value::Enum { value, .. } = result { + if let Value::Struct { fields, .. } = *value { + assert!( + matches!(fields[0], Value::BoundedInt { value, .. } if value == Felt252::from(expected_result)) + ) + } else { + panic!("Test returned an unexpected value"); + } + } else { + panic!("Test returned value was not an Enum as expected"); + } } #[test] From 996bdc552b6493177ba73d984db0a19497f5f7cc Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Fri, 28 Nov 2025 16:21:07 -0300 Subject: [PATCH 12/13] Refactor of tests names --- src/libfuncs/bounded_int.rs | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 21ca34a05..188313dcc 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -882,88 +882,88 @@ mod test { #[feature("bounded-int-utils")] use core::internal::bounded_int::{self, BoundedInt, MulHelper, mul, UnitInt}; - impl MulHelper1 of MulHelper, BoundedInt<-128, 127>> { + impl MulHelperBI_m128x127_BI_m128x127 of MulHelper, BoundedInt<-128, 127>> { type Result = BoundedInt<-16256, 16384>; } - impl MulHelper2 of MulHelper, BoundedInt<0, 128>> { + impl MulHelperBI_0x128_BI_0x128 of MulHelper, BoundedInt<0, 128>> { type Result = BoundedInt<0, 16384>; } - impl MulHelper3 of MulHelper, BoundedInt<1, 1>> { + impl MulHelperBI_1x31_BI_1x1 of MulHelper, BoundedInt<1, 1>> { type Result = BoundedInt<1, 31>; } - impl MulHelper4 of MulHelper, BoundedInt<-1, -1>> { + impl MulHelperBI_m1x31_BI_m1xm1 of MulHelper, BoundedInt<-1, -1>> { type Result = BoundedInt<-31, 1>; } - impl MulHelper5 of MulHelper, BoundedInt<1, 1>> { + impl MulHelperBI_31x31_BI_1x1 of MulHelper, BoundedInt<1, 1>> { type Result = BoundedInt<31, 31>; } - impl MulHelper6 of MulHelper, BoundedInt<0, 100>> { + impl MulHelperBI_m10x0_BI_0x100 of MulHelper, BoundedInt<0, 100>> { type Result = BoundedInt<-10000, 0>; } - impl MulHelper7 of MulHelper, BoundedInt<1, 1>> { + impl MulHelperBI_1x1_BI_1x1 of MulHelper, BoundedInt<1, 1>> { type Result = BoundedInt<1, 1>; } - impl MulHelper8 of MulHelper, UnitInt<2>> { + impl MulHelperBI_m5x5_UI_2 of MulHelper, UnitInt<2>> { type Result = BoundedInt<-10, 10>; } - fn run_test_1(a: felt252, b: felt252) -> BoundedInt<-16256, 16384> { + fn bi_m128x127_times_bi_m128x127(a: felt252, b: felt252) -> BoundedInt<-16256, 16384> { let a: BoundedInt<-128, 127> = a.try_into().unwrap(); let b: BoundedInt<-128, 127> = b.try_into().unwrap(); mul(a,b) } - fn run_test_2(a: felt252, b: felt252) -> BoundedInt<0, 16384> { + fn bi_0x128_times_bi_0x128(a: felt252, b: felt252) -> BoundedInt<0, 16384> { let a: BoundedInt<0, 128> = a.try_into().unwrap(); let b: BoundedInt<0, 128> = b.try_into().unwrap(); mul(a,b) } - fn run_test_3(a: felt252, b: felt252) -> BoundedInt<1, 31> { + fn bi_1x31_times_bi_1x1(a: felt252, b: felt252) -> BoundedInt<1, 31> { let a: BoundedInt<1, 31> = a.try_into().unwrap(); let b: BoundedInt<1, 1> = b.try_into().unwrap(); mul(a,b) } - fn run_test_4(a: felt252, b: felt252) -> BoundedInt<-31, 1> { + fn bi_m1x31_times_bi_m1xm1(a: felt252, b: felt252) -> BoundedInt<-31, 1> { let a: BoundedInt<-1, 31> = a.try_into().unwrap(); let b: BoundedInt<-1, -1> = b.try_into().unwrap(); mul(a,b) } - fn run_test_5(a: felt252, b: felt252) -> BoundedInt<31, 31> { + fn bi_31x31_times_bi_1x1(a: felt252, b: felt252) -> BoundedInt<31, 31> { let a: BoundedInt<31, 31> = a.try_into().unwrap(); let b: BoundedInt<1, 1> = b.try_into().unwrap(); mul(a,b) } - fn run_test_6(a: felt252, b: felt252) -> BoundedInt<-10000, 0> { + fn bi_m100x0_times_bi_0x100(a: felt252, b: felt252) -> BoundedInt<-10000, 0> { let a: BoundedInt<-100, 0> = a.try_into().unwrap(); let b: BoundedInt<0, 100> = b.try_into().unwrap(); mul(a,b) } - fn run_test_7(a: felt252, b: felt252) -> BoundedInt<1, 1> { + fn bi_1x1_times_bi_1x1(a: felt252, b: felt252) -> BoundedInt<1, 1> { let a: BoundedInt<1, 1> = a.try_into().unwrap(); let b: BoundedInt<1, 1> = b.try_into().unwrap(); mul(a,b) } - fn run_test_8(a: felt252, b: felt252) -> BoundedInt<-10, 10> { + fn bi_m5x5_times_ui_2(a: felt252, b: felt252) -> BoundedInt<-10, 10> { let a: BoundedInt<-5, 5> = a.try_into().unwrap(); let b: UnitInt<2> = b.try_into().unwrap(); @@ -972,14 +972,14 @@ mod test { }; } - #[test_case("run_test_1", -128, -128, 16384)] - #[test_case("run_test_2", 126, 128, 16128)] - #[test_case("run_test_3", 31, 1, 31)] - #[test_case("run_test_4", 31, -1, -31)] - #[test_case("run_test_5", 31, 1, 31)] - #[test_case("run_test_6", -100, 100, -10000)] - #[test_case("run_test_7", 1, 1, 1)] - #[test_case("run_test_8", -3, 2, -6)] + #[test_case("bi_m128x127_times_bi_m128x127", -128, -128, 16384)] + #[test_case("bi_0x128_times_bi_0x128", 126, 128, 16128)] + #[test_case("bi_1x31_times_bi_1x1", 31, 1, 31)] + #[test_case("bi_m1x31_times_bi_m1xm1", 31, -1, -31)] + #[test_case("bi_31x31_times_bi_1x1", 31, 1, 31)] + #[test_case("bi_m100x0_times_bi_0x100", -100, 100, -10000)] + #[test_case("bi_1x1_times_bi_1x1", 1, 1, 1)] + #[test_case("bi_m5x5_times_ui_2", -3, 2, -6)] fn test_mul(entry_point: &str, lhs: i32, rhs: i32, expected_result: i32) { let result = run_program( &TEST_MUL_PROGRAM, From 080d21ea9ca28e93f44b700210c6b8077c05f421 Mon Sep 17 00:00:00 2001 From: DiegoC <90105443+DiegoCivi@users.noreply.github.com> Date: Fri, 28 Nov 2025 17:46:28 -0300 Subject: [PATCH 13/13] Update src/libfuncs/bounded_int.rs Co-authored-by: Julian Gonzalez Calderon --- src/libfuncs/bounded_int.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libfuncs/bounded_int.rs b/src/libfuncs/bounded_int.rs index 1322b0468..d5879c590 100644 --- a/src/libfuncs/bounded_int.rs +++ b/src/libfuncs/bounded_int.rs @@ -1003,7 +1003,7 @@ mod test { panic!("Test returned an unexpected value"); } } else { - panic!("Test returned value was not an Enum as expected"); + panic!("Test didn't return an enum as expected"); } }