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