diff --git a/debug_utils/sierra-emu/src/lib.rs b/debug_utils/sierra-emu/src/lib.rs index 2a55372fa8..9aab69f834 100644 --- a/debug_utils/sierra-emu/src/lib.rs +++ b/debug_utils/sierra-emu/src/lib.rs @@ -19,6 +19,7 @@ mod dump; mod gas; pub mod starknet; mod test_utils; +mod utils; mod value; mod vm; diff --git a/debug_utils/sierra-emu/src/utils.rs b/debug_utils/sierra-emu/src/utils.rs new file mode 100644 index 0000000000..fe618ed905 --- /dev/null +++ b/debug_utils/sierra-emu/src/utils.rs @@ -0,0 +1,55 @@ +use cairo_lang_sierra::{ + extensions::core::{CoreLibfunc, CoreType, CoreTypeConcrete}, + program_registry::ProgramRegistry, +}; +use num_bigint::BigInt; +use num_traits::ToPrimitive; + +use crate::Value; + +/// Receives a vector of values, filters any which is non numeric and returns a `Vec` +/// Useful when a binary operation takes generic values (like with bounded ints). +pub fn get_numeric_args_as_bigints(args: &[Value]) -> Vec { + args.iter() + .map(|v| match v { + Value::BoundedInt { value, .. } => value.to_owned(), + Value::I8(value) => BigInt::from(*value), + Value::I16(value) => BigInt::from(*value), + Value::I32(value) => BigInt::from(*value), + Value::I64(value) => BigInt::from(*value), + Value::I128(value) => BigInt::from(*value), + Value::U8(value) => BigInt::from(*value), + Value::U16(value) => BigInt::from(*value), + Value::U32(value) => BigInt::from(*value), + Value::U64(value) => BigInt::from(*value), + Value::U128(value) => BigInt::from(*value), + Value::Felt(value) => value.to_bigint(), + Value::Bytes31(value) => value.to_bigint(), + value => panic!("argument should be an integer: {:?}", value), + }) + .collect() +} + +pub fn get_value_from_integer( + registry: &ProgramRegistry, + ty: &CoreTypeConcrete, + value: BigInt, +) -> Value { + match ty { + CoreTypeConcrete::NonZero(info) => { + let ty = registry.get_type(&info.ty).unwrap(); + get_value_from_integer(registry, ty, value) + } + CoreTypeConcrete::Sint8(_) => Value::I8(value.to_i8().unwrap()), + CoreTypeConcrete::Sint16(_) => Value::I16(value.to_i16().unwrap()), + CoreTypeConcrete::Sint32(_) => Value::I32(value.to_i32().unwrap()), + CoreTypeConcrete::Sint64(_) => Value::I64(value.to_i64().unwrap()), + CoreTypeConcrete::Sint128(_) => Value::I128(value.to_i128().unwrap()), + CoreTypeConcrete::Uint8(_) => Value::U8(value.to_u8().unwrap()), + CoreTypeConcrete::Uint16(_) => Value::U16(value.to_u16().unwrap()), + CoreTypeConcrete::Uint32(_) => Value::U32(value.to_u32().unwrap()), + CoreTypeConcrete::Uint64(_) => Value::U64(value.to_u64().unwrap()), + CoreTypeConcrete::Uint128(_) => Value::U128(value.to_u128().unwrap()), + _ => panic!("cannot get integer value for a non-integer type"), + } +} diff --git a/debug_utils/sierra-emu/src/vm/bounded_int.rs b/debug_utils/sierra-emu/src/vm/bounded_int.rs index 675d2a6f17..55d4955d59 100644 --- a/debug_utils/sierra-emu/src/vm/bounded_int.rs +++ b/debug_utils/sierra-emu/src/vm/bounded_int.rs @@ -1,5 +1,5 @@ use super::EvalAction; -use crate::Value; +use crate::{utils::get_numeric_args_as_bigints, Value}; use cairo_lang_sierra::{ extensions::{ bounded_int::{ @@ -15,29 +15,6 @@ use cairo_lang_sierra::{ use num_bigint::BigInt; use smallvec::smallvec; -// All binary operations have generic arguments, this function takes their values -// and builds bigints out of them (since Bigints are used to represent bounded ints' values) -fn get_numberic_args_as_bigints(args: Vec) -> Vec { - args.into_iter() - // remove builtins, if any - .filter(|v| !matches!(v, Value::Unit)) - .map(|v| match v { - Value::BoundedInt { value, .. } => value, - Value::I8(value) => BigInt::from(value), - Value::I16(value) => BigInt::from(value), - Value::I32(value) => BigInt::from(value), - Value::I64(value) => BigInt::from(value), - Value::I128(value) => BigInt::from(value), - Value::U8(value) => BigInt::from(value), - Value::U16(value) => BigInt::from(value), - Value::U32(value) => BigInt::from(value), - Value::U64(value) => BigInt::from(value), - Value::U128(value) => BigInt::from(value), - _ => panic!("Not a numeric value"), - }) - .collect() -} - pub fn eval( registry: &ProgramRegistry, selector: &BoundedIntConcreteLibfunc, @@ -62,7 +39,7 @@ pub fn eval_add( info: &SignatureOnlyConcreteLibfunc, args: Vec, ) -> EvalAction { - let [lhs, rhs]: [BigInt; 2] = get_numberic_args_as_bigints(args).try_into().unwrap(); + let [lhs, rhs]: [BigInt; 2] = get_numeric_args_as_bigints(&args).try_into().unwrap(); let range = match registry .get_type(&info.signature.branch_signatures[0].vars[0].ty) @@ -91,7 +68,7 @@ pub fn eval_sub( info: &SignatureOnlyConcreteLibfunc, args: Vec, ) -> EvalAction { - let [lhs, rhs]: [BigInt; 2] = get_numberic_args_as_bigints(args).try_into().unwrap(); + let [lhs, rhs]: [BigInt; 2] = get_numeric_args_as_bigints(&args).try_into().unwrap(); let range = match registry .get_type(&info.signature.branch_signatures[0].vars[0].ty) @@ -120,7 +97,7 @@ pub fn eval_mul( info: &SignatureOnlyConcreteLibfunc, args: Vec, ) -> EvalAction { - let [lhs, rhs]: [BigInt; 2] = get_numberic_args_as_bigints(args).try_into().unwrap(); + let [lhs, rhs]: [BigInt; 2] = get_numeric_args_as_bigints(&args).try_into().unwrap(); let range = match registry .get_type(&info.signature.branch_signatures[0].vars[0].ty) @@ -149,7 +126,7 @@ pub fn eval_div_rem( info: &BoundedIntDivRemConcreteLibfunc, args: Vec, ) -> EvalAction { - let [lhs, rhs]: [BigInt; 2] = get_numberic_args_as_bigints(args).try_into().unwrap(); + let [lhs, rhs]: [BigInt; 2] = get_numeric_args_as_bigints(&args).try_into().unwrap(); let quo = &lhs / &rhs; let rem = lhs % rhs; diff --git a/debug_utils/sierra-emu/src/vm/cast.rs b/debug_utils/sierra-emu/src/vm/cast.rs index fd1f15f6fc..78330a5fce 100644 --- a/debug_utils/sierra-emu/src/vm/cast.rs +++ b/debug_utils/sierra-emu/src/vm/cast.rs @@ -1,15 +1,17 @@ use super::EvalAction; -use crate::Value; +use crate::{ + utils::{get_numeric_args_as_bigints, get_value_from_integer}, + Value, +}; use cairo_lang_sierra::{ extensions::{ casts::{CastConcreteLibfunc, DowncastConcreteLibfunc}, - core::{CoreLibfunc, CoreType, CoreTypeConcrete}, + core::{CoreLibfunc, CoreType}, lib_func::SignatureOnlyConcreteLibfunc, - ConcreteType, + ConcreteLibfunc, }, program_registry::ProgramRegistry, }; -use num_bigint::BigInt; use smallvec::smallvec; pub fn eval( @@ -23,85 +25,40 @@ pub fn eval( } } -pub fn eval_downcast( +fn eval_downcast( registry: &ProgramRegistry, info: &DowncastConcreteLibfunc, args: Vec, ) -> EvalAction { - let [range_check @ Value::Unit, value]: [Value; 2] = args.try_into().unwrap() else { + let range_check @ Value::Unit: Value = args[0].clone() else { panic!() }; + let [value] = get_numeric_args_as_bigints(&args[1..]).try_into().unwrap(); - let value = match value { - Value::BoundedInt { value, .. } => value, - Value::U128(value) => BigInt::from(value), - Value::U64(value) => BigInt::from(value), - Value::U32(value) => BigInt::from(value), - Value::U16(value) => BigInt::from(value), - Value::U8(value) => BigInt::from(value), - _ => todo!(), - }; - + let int_ty = registry.get_type(&info.to_ty).unwrap(); let range = info.to_range.lower.clone()..info.to_range.upper.clone(); if range.contains(&value) { EvalAction::NormalBranch( 0, - smallvec![ - range_check, - match registry.get_type(&info.to_ty).unwrap() { - CoreTypeConcrete::Sint8(_) => Value::I8(value.try_into().unwrap()), - CoreTypeConcrete::Sint128(_) => Value::I128(value.try_into().unwrap()), - CoreTypeConcrete::Uint8(_) => Value::U8(value.try_into().unwrap()), - CoreTypeConcrete::Uint16(_) => Value::U16(value.try_into().unwrap()), - CoreTypeConcrete::Uint32(_) => Value::U32(value.try_into().unwrap()), - CoreTypeConcrete::Uint64(_) => Value::U64(value.try_into().unwrap()), - CoreTypeConcrete::Uint128(_) => Value::U128(value.try_into().unwrap()), - CoreTypeConcrete::BoundedInt(_) => Value::BoundedInt { range, value }, - x => todo!("{:?}", x.info()), - } - ], + smallvec![range_check, get_value_from_integer(registry, int_ty, value)], ) } else { EvalAction::NormalBranch(1, smallvec![range_check]) } } -pub fn eval_upcast( +fn eval_upcast( registry: &ProgramRegistry, info: &SignatureOnlyConcreteLibfunc, args: Vec, ) -> EvalAction { - let [value] = args.try_into().unwrap(); - - let value = match value { - Value::BoundedInt { value, .. } => value, - Value::U128(value) => BigInt::from(value), - Value::U64(value) => BigInt::from(value), - Value::U32(value) => BigInt::from(value), - Value::U16(value) => BigInt::from(value), - Value::U8(value) => BigInt::from(value), - _ => todo!(), - }; + let [value] = get_numeric_args_as_bigints(&args).try_into().unwrap(); + let int_ty = registry + .get_type(&info.branch_signatures()[0].vars[0].ty) + .unwrap(); EvalAction::NormalBranch( 0, - smallvec![match registry - .get_type(&info.signature.branch_signatures[0].vars[0].ty) - .unwrap() - { - CoreTypeConcrete::Sint8(_) => Value::I8(value.try_into().unwrap()), - CoreTypeConcrete::Sint32(_) => Value::I32(value.try_into().unwrap()), - CoreTypeConcrete::Sint128(_) => Value::I128(value.try_into().unwrap()), - CoreTypeConcrete::Uint8(_) => Value::U8(value.try_into().unwrap()), - CoreTypeConcrete::Uint16(_) => Value::U16(value.try_into().unwrap()), - CoreTypeConcrete::Uint32(_) => Value::U32(value.try_into().unwrap()), - CoreTypeConcrete::Uint64(_) => Value::U64(value.try_into().unwrap()), - CoreTypeConcrete::Uint128(_) => Value::U128(value.try_into().unwrap()), - CoreTypeConcrete::Felt252(_) => Value::Felt(value.into()), - CoreTypeConcrete::Sint16(_) => todo!("Sint16"), - CoreTypeConcrete::Sint64(_) => todo!("Sint64"), - CoreTypeConcrete::BoundedInt(_) => todo!("BoundedInt"), - _ => todo!(), - }], + smallvec![get_value_from_integer(registry, int_ty, value)], ) } diff --git a/debug_utils/sierra-emu/src/vm/const.rs b/debug_utils/sierra-emu/src/vm/const.rs index be6c24e785..17aac2b970 100644 --- a/debug_utils/sierra-emu/src/vm/const.rs +++ b/debug_utils/sierra-emu/src/vm/const.rs @@ -6,11 +6,13 @@ use cairo_lang_sierra::{ ConstAsBoxConcreteLibfunc, ConstAsImmediateConcreteLibfunc, ConstConcreteLibfunc, }, core::{CoreLibfunc, CoreType, CoreTypeConcrete}, + starknet::StarknetTypeConcrete, }, ids::ConcreteTypeId, program::GenericArg, program_registry::ProgramRegistry, }; +use num_traits::ToPrimitive; use smallvec::smallvec; pub fn eval( @@ -24,7 +26,7 @@ pub fn eval( } } -pub fn eval_as_immediate( +fn eval_as_immediate( registry: &ProgramRegistry, info: &ConstAsImmediateConcreteLibfunc, args: Vec, @@ -41,7 +43,7 @@ pub fn eval_as_immediate( ) } -pub fn eval_as_box( +fn eval_as_box( registry: &ProgramRegistry, info: &ConstAsBoxConcreteLibfunc, args: Vec, @@ -89,28 +91,32 @@ fn inner( }, _ => unreachable!(), }, + CoreTypeConcrete::Bytes31(_) => match inner_data { + [GenericArg::Value(value)] => Value::Bytes31(value.into()), + _ => unreachable!(), + }, CoreTypeConcrete::Sint128(_) => match inner_data { - [GenericArg::Value(value)] => Value::I128(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::I128(value.to_i128().unwrap()), _ => unreachable!(), }, CoreTypeConcrete::Sint64(_) => match inner_data { - [GenericArg::Value(value)] => Value::U64(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::I64(value.to_i64().unwrap()), _ => unreachable!(), }, CoreTypeConcrete::Sint32(_) => match inner_data { - [GenericArg::Value(value)] => Value::I32(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::I32(value.to_i32().unwrap()), _ => unreachable!(), }, CoreTypeConcrete::Sint16(_) => match inner_data { - [GenericArg::Value(value)] => Value::I16(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::I16(value.to_i16().unwrap()), _ => unreachable!(), }, CoreTypeConcrete::Sint8(_) => match inner_data { - [GenericArg::Value(value)] => Value::I8(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::I8(value.to_i8().unwrap()), _ => unreachable!(), }, CoreTypeConcrete::Uint128(_) => match inner_data { - [GenericArg::Value(value)] => Value::U128(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::U128(value.to_u128().unwrap()), [GenericArg::Type(type_id)] => match registry.get_type(type_id).unwrap() { CoreTypeConcrete::Const(info) => inner(registry, &info.inner_ty, &info.inner_data), _ => unreachable!(), @@ -118,11 +124,11 @@ fn inner( _ => unreachable!(), }, CoreTypeConcrete::Uint64(_) => match inner_data { - [GenericArg::Value(value)] => Value::U64(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::U64(value.to_u64().unwrap()), _ => unreachable!(), }, CoreTypeConcrete::Uint32(_) => match inner_data { - [GenericArg::Value(value)] => Value::U32(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::U32(value.to_u32().unwrap()), [GenericArg::Type(type_id)] => match registry.get_type(type_id).unwrap() { CoreTypeConcrete::Const(info) => inner(registry, &info.inner_ty, &info.inner_data), _ => unreachable!(), @@ -130,11 +136,11 @@ fn inner( _ => unreachable!(), }, CoreTypeConcrete::Uint16(_) => match inner_data { - [GenericArg::Value(value)] => Value::U16(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::U16(value.to_u16().unwrap()), _ => unreachable!(), }, CoreTypeConcrete::Uint8(_) => match inner_data { - [GenericArg::Value(value)] => Value::U8(value.try_into().unwrap()), + [GenericArg::Value(value)] => Value::U8(value.to_u8().unwrap()), _ => unreachable!(), }, CoreTypeConcrete::Struct(_) => { @@ -160,6 +166,37 @@ fn inner( Value::Struct(fields) } + CoreTypeConcrete::Enum(_) => match inner_data { + [GenericArg::Value(value_idx), GenericArg::Type(payload_ty)] => { + let payload_type = registry.get_type(payload_ty).unwrap(); + let const_payload_type = match payload_type { + CoreTypeConcrete::Const(inner) => inner, + _ => { + panic!("matched an unexpected CoreTypeConcrete that is not a Const") + } + }; + let payload = inner(registry, payload_ty, &const_payload_type.inner_data); + let index: usize = value_idx.to_usize().unwrap(); + + Value::Enum { + self_ty: type_id.clone(), + index, + payload: Box::new(payload), + } + } + _ => panic!("const data mismatch"), + }, + CoreTypeConcrete::Const(info) => inner(registry, &info.inner_ty, &info.inner_data), + CoreTypeConcrete::Starknet(selector) => match selector { + StarknetTypeConcrete::ClassHash(_) + | StarknetTypeConcrete::ContractAddress(_) + | StarknetTypeConcrete::StorageAddress(_) + | StarknetTypeConcrete::StorageBaseAddress(_) => match inner_data { + [GenericArg::Value(value)] => Value::Felt(value.into()), + _ => unreachable!(), + }, + _ => todo!(""), + }, _ => todo!("{}", type_id), } }