cairo_lang_sierra/extensions/modules/int/
unsigned.rs1use std::marker::PhantomData;
2
3use super::unsigned128::Uint128Type;
4use super::{
5 IntConstLibfunc, IntEqualLibfunc, IntFromFelt252Libfunc, IntMulTraits,
6 IntOperationConcreteLibfunc, IntOperator, IntToFelt252Libfunc, IntTraits, IntType,
7 IntWideMulLibfunc,
8};
9use crate::define_libfunc_hierarchy;
10use crate::extensions::bitwise::BitwiseType;
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::non_zero::nonzero_ty;
17use crate::extensions::range_check::RangeCheckType;
18use crate::extensions::{
19 GenericLibfunc, NamedType, NoGenericArgsGenericLibfunc, OutputVarReferenceInfo,
20 SpecializationError,
21};
22use crate::ids::{GenericLibfuncId, GenericTypeId};
23use crate::program::GenericArg;
24
25pub trait UintTraits: IntTraits {
27 const OVERFLOWING_ADD: &'static str;
29 const OVERFLOWING_SUB: &'static str;
31 const SQUARE_ROOT: &'static str;
33 const SQUARE_ROOT_TYPE_ID: GenericTypeId;
35 const DIVMOD: &'static str;
37 const BITWISE: &'static str;
39}
40
41pub struct UintOperationLibfunc<TUintTraits: UintTraits> {
43 pub operator: IntOperator,
44 _phantom: PhantomData<TUintTraits>,
45}
46impl<TUintTraits: UintTraits> UintOperationLibfunc<TUintTraits> {
47 const OVERFLOWING_ADD: &'static str = TUintTraits::OVERFLOWING_ADD;
48 const OVERFLOWING_SUB: &'static str = TUintTraits::OVERFLOWING_SUB;
49 fn new(operator: IntOperator) -> Option<Self> {
50 Some(Self { operator, _phantom: PhantomData })
51 }
52}
53impl<TUintTraits: UintTraits> GenericLibfunc for UintOperationLibfunc<TUintTraits> {
54 type Concrete = IntOperationConcreteLibfunc;
55
56 fn supported_ids() -> Vec<GenericLibfuncId> {
57 vec![
58 GenericLibfuncId::from(Self::OVERFLOWING_ADD),
59 GenericLibfuncId::from(Self::OVERFLOWING_SUB),
60 ]
61 }
62
63 fn by_id(id: &GenericLibfuncId) -> Option<Self> {
64 match id.0.as_str() {
65 id if id == Self::OVERFLOWING_ADD => Self::new(IntOperator::OverflowingAdd),
66 id if id == Self::OVERFLOWING_SUB => Self::new(IntOperator::OverflowingSub),
67 _ => None,
68 }
69 }
70
71 fn specialize_signature(
72 &self,
73 context: &dyn SignatureSpecializationContext,
74 args: &[GenericArg],
75 ) -> Result<LibfuncSignature, SpecializationError> {
76 if !args.is_empty() {
77 return Err(SpecializationError::WrongNumberOfGenericArgs);
78 }
79 let ty = context.get_concrete_type(TUintTraits::GENERIC_TYPE_ID, &[])?;
80 let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
81
82 let wrapping_result_ref_info = match (self.operator, TUintTraits::IS_SMALL) {
83 (IntOperator::OverflowingSub, true) => {
84 OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic)
85 }
86 (IntOperator::OverflowingAdd, false)
87 | (IntOperator::OverflowingAdd, true)
88 | (IntOperator::OverflowingSub, false) => OutputVarReferenceInfo::NewTempVar { idx: 0 },
89 };
90
91 let rc_output_info = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
92 let ty_param = ParamSignature::new(ty.clone());
93 Ok(LibfuncSignature {
94 param_signatures: vec![
95 ParamSignature::new(range_check_type).with_allow_add_const(),
96 ty_param.clone(),
97 ty_param,
98 ],
99 branch_signatures: vec![
100 BranchSignature {
101 vars: vec![rc_output_info.clone(), OutputVarInfo {
102 ty: ty.clone(),
103 ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
104 }],
105 ap_change: SierraApChange::Known { new_vars_only: false },
106 },
107 BranchSignature {
108 vars: vec![rc_output_info, OutputVarInfo {
109 ty,
110 ref_info: wrapping_result_ref_info,
111 }],
112 ap_change: SierraApChange::Known { new_vars_only: false },
113 },
114 ],
115 fallthrough: Some(0),
116 })
117 }
118
119 fn specialize(
120 &self,
121 context: &dyn SpecializationContext,
122 args: &[GenericArg],
123 ) -> Result<Self::Concrete, SpecializationError> {
124 Ok(IntOperationConcreteLibfunc {
125 operator: self.operator,
126 signature: self.specialize_signature(context.upcast(), args)?,
127 })
128 }
129}
130
131#[derive(Default)]
133pub struct UintSquareRootLibfunc<TUintTraits: UintTraits> {
134 _phantom: PhantomData<TUintTraits>,
135}
136impl<TUintTraits: UintTraits> NoGenericArgsGenericLibfunc for UintSquareRootLibfunc<TUintTraits> {
137 const STR_ID: &'static str = TUintTraits::SQUARE_ROOT;
138
139 fn specialize_signature(
140 &self,
141 context: &dyn SignatureSpecializationContext,
142 ) -> Result<LibfuncSignature, SpecializationError> {
143 let ty = context.get_concrete_type(TUintTraits::GENERIC_TYPE_ID, &[])?;
144 let sqrt_ty = context.get_concrete_type(TUintTraits::SQUARE_ROOT_TYPE_ID, &[])?;
145 let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
146 Ok(LibfuncSignature::new_non_branch_ex(
147 vec![
148 ParamSignature::new(range_check_type.clone()).with_allow_add_const(),
149 ParamSignature::new(ty),
150 ],
151 vec![OutputVarInfo::new_builtin(range_check_type, 0), OutputVarInfo {
152 ty: sqrt_ty,
153 ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
154 }],
155 SierraApChange::Known { new_vars_only: false },
156 ))
157 }
158}
159
160#[derive(Default)]
162pub struct UintDivmodLibfunc<TUintTraits: UintTraits> {
163 _phantom: PhantomData<TUintTraits>,
164}
165impl<TUintTraits: UintTraits> NoGenericArgsGenericLibfunc for UintDivmodLibfunc<TUintTraits> {
166 const STR_ID: &'static str = TUintTraits::DIVMOD;
167
168 fn specialize_signature(
169 &self,
170 context: &dyn SignatureSpecializationContext,
171 ) -> Result<LibfuncSignature, SpecializationError> {
172 let ty = context.get_concrete_type(TUintTraits::GENERIC_TYPE_ID, &[])?;
173 let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
174 Ok(LibfuncSignature::new_non_branch_ex(
175 vec![
176 ParamSignature::new(range_check_type.clone()).with_allow_add_const(),
177 ParamSignature::new(ty.clone()),
178 ParamSignature::new(nonzero_ty(context, &ty)?),
179 ],
180 vec![
181 OutputVarInfo::new_builtin(range_check_type, 0),
182 OutputVarInfo {
183 ty: ty.clone(),
184 ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
185 },
186 OutputVarInfo { ty, ref_info: OutputVarReferenceInfo::NewTempVar { idx: 1 } },
187 ],
188 SierraApChange::Known { new_vars_only: false },
189 ))
190 }
191}
192
193#[derive(Default)]
196pub struct UintBitwiseLibfunc<TUintTraits: UintTraits> {
197 _phantom: PhantomData<TUintTraits>,
198}
199impl<TUintTraits: UintTraits> NoGenericArgsGenericLibfunc for UintBitwiseLibfunc<TUintTraits> {
200 const STR_ID: &'static str = TUintTraits::BITWISE;
201
202 fn specialize_signature(
203 &self,
204 context: &dyn SignatureSpecializationContext,
205 ) -> Result<LibfuncSignature, SpecializationError> {
206 let bitwise_ty = context.get_concrete_type(BitwiseType::id(), &[])?;
207 let ty = context.get_concrete_type(TUintTraits::GENERIC_TYPE_ID, &[])?;
208 let deferred_ty_output_info = OutputVarInfo {
209 ty: ty.clone(),
210 ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
211 };
212 let ty_param = ParamSignature::new(ty);
213 Ok(LibfuncSignature::new_non_branch_ex(
214 vec![
215 ParamSignature::new(bitwise_ty.clone()).with_allow_add_const(),
216 ty_param.clone(),
217 ty_param,
218 ],
219 vec![
220 OutputVarInfo::new_builtin(bitwise_ty, 0),
221 deferred_ty_output_info.clone(),
222 deferred_ty_output_info.clone(),
223 deferred_ty_output_info,
224 ],
225 SierraApChange::Known { new_vars_only: true },
226 ))
227 }
228}
229
230define_libfunc_hierarchy! {
231 pub enum UintLibfunc<TUintTraits: UintTraits + IntMulTraits + IsZeroTraits> {
232 Const(IntConstLibfunc<TUintTraits>),
233 Operation(UintOperationLibfunc<TUintTraits>),
234 SquareRoot(UintSquareRootLibfunc<TUintTraits>),
235 Equal(IntEqualLibfunc<TUintTraits>),
236 ToFelt252(IntToFelt252Libfunc<TUintTraits>),
237 FromFelt252(IntFromFelt252Libfunc<TUintTraits>),
238 IsZero(IsZeroLibfunc<TUintTraits>),
239 Divmod(UintDivmodLibfunc<TUintTraits>),
240 WideMul(IntWideMulLibfunc<TUintTraits>),
241 Bitwise(UintBitwiseLibfunc<TUintTraits>),
242 }, UintConcrete
243}
244
245#[derive(Default)]
246pub struct Uint8Traits;
247
248impl IntTraits for Uint8Traits {
249 type IntType = u8;
250 const GENERIC_TYPE_ID: GenericTypeId = GenericTypeId::new_inline("u8");
251 const IS_SMALL: bool = true;
252 const CONST: &'static str = "u8_const";
253 const EQUAL: &'static str = "u8_eq";
254 const TO_FELT252: &'static str = "u8_to_felt252";
255 const TRY_FROM_FELT252: &'static str = "u8_try_from_felt252";
256}
257
258impl UintTraits for Uint8Traits {
259 const OVERFLOWING_ADD: &'static str = "u8_overflowing_add";
260 const OVERFLOWING_SUB: &'static str = "u8_overflowing_sub";
261 const SQUARE_ROOT: &'static str = "u8_sqrt";
262 const SQUARE_ROOT_TYPE_ID: GenericTypeId = <Self as IntTraits>::GENERIC_TYPE_ID;
263 const DIVMOD: &'static str = "u8_safe_divmod";
264 const BITWISE: &'static str = "u8_bitwise";
265}
266
267impl IntMulTraits for Uint8Traits {
268 const WIDE_MUL: &'static str = "u8_wide_mul";
269 const WIDE_MUL_RES_TYPE_ID: GenericTypeId = <Uint16Type as NamedType>::ID;
270}
271
272impl IsZeroTraits for Uint8Traits {
273 const IS_ZERO: &'static str = "u8_is_zero";
274 const GENERIC_TYPE_ID: GenericTypeId = <Uint8Type as NamedType>::ID;
275}
276
277pub type Uint8Type = IntType<Uint8Traits>;
279pub type Uint8Libfunc = UintLibfunc<Uint8Traits>;
280pub type Uint8Concrete = <Uint8Libfunc as GenericLibfunc>::Concrete;
281
282#[derive(Default)]
283pub struct Uint16Traits;
284
285impl IntTraits for Uint16Traits {
286 type IntType = u16;
287 const GENERIC_TYPE_ID: GenericTypeId = GenericTypeId::new_inline("u16");
288 const IS_SMALL: bool = true;
289 const CONST: &'static str = "u16_const";
290 const EQUAL: &'static str = "u16_eq";
291 const TO_FELT252: &'static str = "u16_to_felt252";
292 const TRY_FROM_FELT252: &'static str = "u16_try_from_felt252";
293}
294
295impl UintTraits for Uint16Traits {
296 const OVERFLOWING_ADD: &'static str = "u16_overflowing_add";
297 const OVERFLOWING_SUB: &'static str = "u16_overflowing_sub";
298 const SQUARE_ROOT: &'static str = "u16_sqrt";
299 const SQUARE_ROOT_TYPE_ID: GenericTypeId = <Uint8Type as NamedType>::ID;
300 const DIVMOD: &'static str = "u16_safe_divmod";
301 const BITWISE: &'static str = "u16_bitwise";
302}
303
304impl IntMulTraits for Uint16Traits {
305 const WIDE_MUL: &'static str = "u16_wide_mul";
306 const WIDE_MUL_RES_TYPE_ID: GenericTypeId = <Uint32Type as NamedType>::ID;
307}
308
309impl IsZeroTraits for Uint16Traits {
310 const IS_ZERO: &'static str = "u16_is_zero";
311 const GENERIC_TYPE_ID: GenericTypeId = <Uint16Type as NamedType>::ID;
312}
313
314pub type Uint16Type = IntType<Uint16Traits>;
316pub type Uint16Libfunc = UintLibfunc<Uint16Traits>;
317pub type Uint16Concrete = <Uint16Libfunc as GenericLibfunc>::Concrete;
318
319#[derive(Default)]
320pub struct Uint32Traits;
321
322impl IntTraits for Uint32Traits {
323 type IntType = u32;
324 const GENERIC_TYPE_ID: GenericTypeId = GenericTypeId::new_inline("u32");
325 const IS_SMALL: bool = true;
326 const CONST: &'static str = "u32_const";
327 const EQUAL: &'static str = "u32_eq";
328 const TO_FELT252: &'static str = "u32_to_felt252";
329 const TRY_FROM_FELT252: &'static str = "u32_try_from_felt252";
330}
331
332impl UintTraits for Uint32Traits {
333 const OVERFLOWING_ADD: &'static str = "u32_overflowing_add";
334 const OVERFLOWING_SUB: &'static str = "u32_overflowing_sub";
335 const SQUARE_ROOT: &'static str = "u32_sqrt";
336 const SQUARE_ROOT_TYPE_ID: GenericTypeId = <Uint16Type as NamedType>::ID;
337 const DIVMOD: &'static str = "u32_safe_divmod";
338 const BITWISE: &'static str = "u32_bitwise";
339}
340
341impl IntMulTraits for Uint32Traits {
342 const WIDE_MUL: &'static str = "u32_wide_mul";
343 const WIDE_MUL_RES_TYPE_ID: GenericTypeId = <Uint64Type as NamedType>::ID;
344}
345
346impl IsZeroTraits for Uint32Traits {
347 const IS_ZERO: &'static str = "u32_is_zero";
348 const GENERIC_TYPE_ID: GenericTypeId = <Uint32Type as NamedType>::ID;
349}
350
351pub type Uint32Type = IntType<Uint32Traits>;
353pub type Uint32Libfunc = UintLibfunc<Uint32Traits>;
354pub type Uint32Concrete = <Uint32Libfunc as GenericLibfunc>::Concrete;
355
356#[derive(Default)]
357pub struct Uint64Traits;
358
359impl IntTraits for Uint64Traits {
360 type IntType = u64;
361 const GENERIC_TYPE_ID: GenericTypeId = GenericTypeId::new_inline("u64");
362 const IS_SMALL: bool = true;
363 const CONST: &'static str = "u64_const";
364 const EQUAL: &'static str = "u64_eq";
365 const TO_FELT252: &'static str = "u64_to_felt252";
366 const TRY_FROM_FELT252: &'static str = "u64_try_from_felt252";
367}
368
369impl UintTraits for Uint64Traits {
370 const OVERFLOWING_ADD: &'static str = "u64_overflowing_add";
371 const OVERFLOWING_SUB: &'static str = "u64_overflowing_sub";
372 const SQUARE_ROOT: &'static str = "u64_sqrt";
373 const SQUARE_ROOT_TYPE_ID: GenericTypeId = <Uint32Type as NamedType>::ID;
374 const DIVMOD: &'static str = "u64_safe_divmod";
375 const BITWISE: &'static str = "u64_bitwise";
376}
377
378impl IntMulTraits for Uint64Traits {
379 const WIDE_MUL: &'static str = "u64_wide_mul";
380 const WIDE_MUL_RES_TYPE_ID: GenericTypeId = <Uint128Type as NamedType>::ID;
381}
382
383impl IsZeroTraits for Uint64Traits {
384 const IS_ZERO: &'static str = "u64_is_zero";
385 const GENERIC_TYPE_ID: GenericTypeId = <Uint64Type as NamedType>::ID;
386}
387
388pub type Uint64Type = IntType<Uint64Traits>;
390pub type Uint64Libfunc = UintLibfunc<Uint64Traits>;
391pub type Uint64Concrete = <Uint64Libfunc as GenericLibfunc>::Concrete;