cairo_lang_sierra/extensions/modules/int/
signed.rs

1use std::marker::PhantomData;
2
3use super::signed128::Sint128Type;
4use super::unsigned::{Uint8Type, Uint16Type, Uint32Type, Uint64Type};
5use super::{
6    IntConstLibfunc, IntEqualLibfunc, IntFromFelt252Libfunc, IntMulTraits,
7    IntOperationConcreteLibfunc, IntOperator, IntToFelt252Libfunc, IntTraits, IntType,
8    IntWideMulLibfunc,
9};
10use crate::define_libfunc_hierarchy;
11use crate::extensions::lib_func::{
12    BranchSignature, DeferredOutputKind, LibfuncSignature, OutputVarInfo, ParamSignature,
13    SierraApChange, SignatureSpecializationContext, SpecializationContext,
14};
15use crate::extensions::range_check::RangeCheckType;
16use crate::extensions::{
17    GenericLibfunc, NamedType, NoGenericArgsGenericLibfunc, OutputVarReferenceInfo,
18    SpecializationError,
19};
20use crate::ids::{GenericLibfuncId, GenericTypeId};
21use crate::program::GenericArg;
22
23/// Trait for implementing signed integers.
24pub trait SintTraits: IntTraits {
25    /// The generic libfunc id for addition.
26    const OVERFLOWING_ADD: &'static str;
27    /// The generic libfunc id for subtraction.
28    const OVERFLOWING_SUB: &'static str;
29    /// The generic libfunc id for difference of signed integers, logically equivalent to
30    /// subtraction of unsigned integers.
31    const DIFF: &'static str;
32    /// The generic type id of the equivalent unsigned integer type.
33    const UNSIGNED_INT_TYPE: GenericTypeId;
34}
35
36define_libfunc_hierarchy! {
37    pub enum SintLibfunc<TSintTraits: SintTraits + IntMulTraits> {
38        Const(IntConstLibfunc<TSintTraits>),
39        Equal(IntEqualLibfunc<TSintTraits>),
40        ToFelt252(IntToFelt252Libfunc<TSintTraits>),
41        FromFelt252(IntFromFelt252Libfunc<TSintTraits>),
42        Operation(SintOperationLibfunc<TSintTraits>),
43        Diff(SintDiffLibfunc<TSintTraits>),
44        WideMul(IntWideMulLibfunc<TSintTraits>),
45    }, SintConcrete
46}
47
48/// Libfunc for integer operations.
49pub struct SintOperationLibfunc<TSintTraits: SintTraits> {
50    pub operator: IntOperator,
51    _phantom: PhantomData<TSintTraits>,
52}
53impl<TSintTraits: SintTraits> SintOperationLibfunc<TSintTraits> {
54    const OVERFLOWING_ADD: &'static str = TSintTraits::OVERFLOWING_ADD;
55    const OVERFLOWING_SUB: &'static str = TSintTraits::OVERFLOWING_SUB;
56    fn new(operator: IntOperator) -> Option<Self> {
57        Some(Self { operator, _phantom: PhantomData })
58    }
59}
60impl<TSintTraits: SintTraits> GenericLibfunc for SintOperationLibfunc<TSintTraits> {
61    type Concrete = IntOperationConcreteLibfunc;
62
63    fn supported_ids() -> Vec<GenericLibfuncId> {
64        vec![
65            GenericLibfuncId::from(Self::OVERFLOWING_ADD),
66            GenericLibfuncId::from(Self::OVERFLOWING_SUB),
67        ]
68    }
69
70    fn by_id(id: &GenericLibfuncId) -> Option<Self> {
71        match id.0.as_str() {
72            id if id == Self::OVERFLOWING_ADD => Self::new(IntOperator::OverflowingAdd),
73            id if id == Self::OVERFLOWING_SUB => Self::new(IntOperator::OverflowingSub),
74            _ => None,
75        }
76    }
77
78    fn specialize_signature(
79        &self,
80        context: &dyn SignatureSpecializationContext,
81        args: &[GenericArg],
82    ) -> Result<LibfuncSignature, SpecializationError> {
83        if !args.is_empty() {
84            return Err(SpecializationError::WrongNumberOfGenericArgs);
85        }
86        let ty = context.get_concrete_type(TSintTraits::GENERIC_TYPE_ID, &[])?;
87        let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
88
89        let ty_param = ParamSignature::new(ty.clone());
90        let rc_output_info = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
91        let wrapping_result_info = OutputVarInfo {
92            ty: ty.clone(),
93            ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
94        };
95        Ok(LibfuncSignature {
96            param_signatures: vec![
97                ParamSignature::new(range_check_type).with_allow_add_const(),
98                ty_param.clone(),
99                ty_param,
100            ],
101            branch_signatures: vec![
102                // In range.
103                BranchSignature {
104                    vars: vec![
105                        rc_output_info.clone(),
106                        OutputVarInfo { ty, ref_info: OutputVarReferenceInfo::SimpleDerefs },
107                    ],
108                    ap_change: SierraApChange::Known { new_vars_only: false },
109                },
110                // Below range.
111                BranchSignature {
112                    vars: vec![rc_output_info.clone(), wrapping_result_info.clone()],
113                    ap_change: SierraApChange::Known { new_vars_only: false },
114                },
115                // Above range.
116                BranchSignature {
117                    vars: vec![rc_output_info, wrapping_result_info],
118                    ap_change: SierraApChange::Known { new_vars_only: false },
119                },
120            ],
121            fallthrough: Some(0),
122        })
123    }
124
125    fn specialize(
126        &self,
127        context: &dyn SpecializationContext,
128        args: &[GenericArg],
129    ) -> Result<Self::Concrete, SpecializationError> {
130        Ok(IntOperationConcreteLibfunc {
131            operator: self.operator,
132            signature: self.specialize_signature(context.upcast(), args)?,
133        })
134    }
135}
136
137/// Libfunc for integer difference calculation.
138#[derive(Default)]
139pub struct SintDiffLibfunc<TSintTraits: SintTraits> {
140    _phantom: PhantomData<TSintTraits>,
141}
142impl<TSintTraits: SintTraits> NoGenericArgsGenericLibfunc for SintDiffLibfunc<TSintTraits> {
143    const STR_ID: &'static str = TSintTraits::DIFF;
144
145    fn specialize_signature(
146        &self,
147        context: &dyn SignatureSpecializationContext,
148    ) -> Result<LibfuncSignature, SpecializationError> {
149        let signed_ty = context.get_concrete_type(TSintTraits::GENERIC_TYPE_ID, &[])?;
150        let unsigned_ty = context.get_concrete_type(TSintTraits::UNSIGNED_INT_TYPE, &[])?;
151        let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
152
153        let signed_ty_param = ParamSignature::new(signed_ty);
154        let rc_output_info = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
155        let wrapping_result_ref_info = if TSintTraits::IS_SMALL {
156            OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic)
157        } else {
158            OutputVarReferenceInfo::NewTempVar { idx: 0 }
159        };
160        Ok(LibfuncSignature {
161            param_signatures: vec![
162                ParamSignature::new(range_check_type).with_allow_add_const(),
163                signed_ty_param.clone(),
164                signed_ty_param,
165            ],
166            branch_signatures: vec![
167                // Positive.
168                BranchSignature {
169                    vars: vec![
170                        rc_output_info.clone(),
171                        OutputVarInfo {
172                            ty: unsigned_ty.clone(),
173                            ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
174                        },
175                    ],
176                    ap_change: SierraApChange::Known { new_vars_only: false },
177                },
178                // Negative.
179                BranchSignature {
180                    vars: vec![
181                        rc_output_info,
182                        OutputVarInfo { ty: unsigned_ty, ref_info: wrapping_result_ref_info },
183                    ],
184                    ap_change: SierraApChange::Known { new_vars_only: false },
185                },
186            ],
187            fallthrough: Some(0),
188        })
189    }
190}
191
192#[derive(Default)]
193pub struct Sint8Traits;
194
195impl SintTraits for Sint8Traits {
196    const OVERFLOWING_ADD: &'static str = "i8_overflowing_add_impl";
197    const OVERFLOWING_SUB: &'static str = "i8_overflowing_sub_impl";
198    const DIFF: &'static str = "i8_diff";
199    const UNSIGNED_INT_TYPE: GenericTypeId = <Uint8Type as NamedType>::ID;
200}
201
202impl IntTraits for Sint8Traits {
203    type IntType = i8;
204    const GENERIC_TYPE_ID: GenericTypeId = GenericTypeId::new_inline("i8");
205    const IS_SMALL: bool = true;
206    const CONST: &'static str = "i8_const";
207    const EQUAL: &'static str = "i8_eq";
208    const TO_FELT252: &'static str = "i8_to_felt252";
209    const TRY_FROM_FELT252: &'static str = "i8_try_from_felt252";
210}
211
212impl IntMulTraits for Sint8Traits {
213    const WIDE_MUL: &'static str = "i8_wide_mul";
214    const WIDE_MUL_RES_TYPE_ID: GenericTypeId = <Sint16Type as NamedType>::ID;
215}
216
217/// Type for i8.
218pub type Sint8Type = IntType<Sint8Traits>;
219pub type Sint8Libfunc = SintLibfunc<Sint8Traits>;
220pub type Sint8Concrete = <Sint8Libfunc as GenericLibfunc>::Concrete;
221
222#[derive(Default)]
223pub struct Sint16Traits;
224
225impl SintTraits for Sint16Traits {
226    const OVERFLOWING_ADD: &'static str = "i16_overflowing_add_impl";
227    const OVERFLOWING_SUB: &'static str = "i16_overflowing_sub_impl";
228    const DIFF: &'static str = "i16_diff";
229    const UNSIGNED_INT_TYPE: GenericTypeId = <Uint16Type as NamedType>::ID;
230}
231
232impl IntTraits for Sint16Traits {
233    type IntType = i16;
234    const GENERIC_TYPE_ID: GenericTypeId = GenericTypeId::new_inline("i16");
235    const IS_SMALL: bool = true;
236    const CONST: &'static str = "i16_const";
237    const EQUAL: &'static str = "i16_eq";
238    const TO_FELT252: &'static str = "i16_to_felt252";
239    const TRY_FROM_FELT252: &'static str = "i16_try_from_felt252";
240}
241
242impl IntMulTraits for Sint16Traits {
243    const WIDE_MUL: &'static str = "i16_wide_mul";
244    const WIDE_MUL_RES_TYPE_ID: GenericTypeId = <Sint32Type as NamedType>::ID;
245}
246
247/// Type for i16.
248pub type Sint16Type = IntType<Sint16Traits>;
249pub type Sint16Libfunc = SintLibfunc<Sint16Traits>;
250pub type Sint16Concrete = <Sint16Libfunc as GenericLibfunc>::Concrete;
251
252#[derive(Default)]
253pub struct Sint32Traits;
254
255impl SintTraits for Sint32Traits {
256    const OVERFLOWING_ADD: &'static str = "i32_overflowing_add_impl";
257    const OVERFLOWING_SUB: &'static str = "i32_overflowing_sub_impl";
258    const DIFF: &'static str = "i32_diff";
259    const UNSIGNED_INT_TYPE: GenericTypeId = <Uint32Type as NamedType>::ID;
260}
261
262impl IntTraits for Sint32Traits {
263    type IntType = i32;
264    const GENERIC_TYPE_ID: GenericTypeId = GenericTypeId::new_inline("i32");
265    const IS_SMALL: bool = true;
266    const CONST: &'static str = "i32_const";
267    const EQUAL: &'static str = "i32_eq";
268    const TO_FELT252: &'static str = "i32_to_felt252";
269    const TRY_FROM_FELT252: &'static str = "i32_try_from_felt252";
270}
271
272impl IntMulTraits for Sint32Traits {
273    const WIDE_MUL: &'static str = "i32_wide_mul";
274    const WIDE_MUL_RES_TYPE_ID: GenericTypeId = <Sint64Type as NamedType>::ID;
275}
276
277/// Type for i32.
278pub type Sint32Type = IntType<Sint32Traits>;
279pub type Sint32Libfunc = SintLibfunc<Sint32Traits>;
280pub type Sint32Concrete = <Sint32Libfunc as GenericLibfunc>::Concrete;
281
282#[derive(Default)]
283pub struct Sint64Traits;
284
285impl SintTraits for Sint64Traits {
286    const OVERFLOWING_ADD: &'static str = "i64_overflowing_add_impl";
287    const OVERFLOWING_SUB: &'static str = "i64_overflowing_sub_impl";
288    const DIFF: &'static str = "i64_diff";
289    const UNSIGNED_INT_TYPE: GenericTypeId = <Uint64Type as NamedType>::ID;
290}
291
292impl IntTraits for Sint64Traits {
293    type IntType = i64;
294    const GENERIC_TYPE_ID: GenericTypeId = GenericTypeId::new_inline("i64");
295    const IS_SMALL: bool = true;
296    const CONST: &'static str = "i64_const";
297    const EQUAL: &'static str = "i64_eq";
298    const TO_FELT252: &'static str = "i64_to_felt252";
299    const TRY_FROM_FELT252: &'static str = "i64_try_from_felt252";
300}
301
302impl IntMulTraits for Sint64Traits {
303    const WIDE_MUL: &'static str = "i64_wide_mul";
304    const WIDE_MUL_RES_TYPE_ID: GenericTypeId = <Sint128Type as NamedType>::ID;
305}
306
307/// Type for i64.
308pub type Sint64Type = IntType<Sint64Traits>;
309pub type Sint64Libfunc = SintLibfunc<Sint64Traits>;
310pub type Sint64Concrete = <Sint64Libfunc as GenericLibfunc>::Concrete;