-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
document todos and implement bytes31 (#392)
* document todos and implement bytes31 * layout * suggestion and fixes
- Loading branch information
Showing
10 changed files
with
313 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
//! # Struct-related libfuncs | ||
use super::{LibfuncBuilder, LibfuncHelper}; | ||
use crate::{ | ||
error::{ | ||
libfuncs::{Error, Result}, | ||
CoreTypeBuilderError, | ||
}, | ||
metadata::MetadataStorage, | ||
types::TypeBuilder, | ||
utils::ProgramRegistryExt, | ||
}; | ||
use cairo_lang_sierra::{ | ||
extensions::{ | ||
bytes31::Bytes31ConcreteLibfunc, consts::SignatureAndConstConcreteLibfunc, | ||
lib_func::SignatureOnlyConcreteLibfunc, ConcreteLibfunc, GenericLibfunc, GenericType, | ||
}, | ||
program_registry::ProgramRegistry, | ||
}; | ||
use melior::{ | ||
dialect::{ | ||
arith::{self, CmpiPredicate}, | ||
cf, | ||
}, | ||
ir::{Attribute, Block, Location, Value}, | ||
Context, | ||
}; | ||
use num_bigint::BigUint; | ||
|
||
/// Select and call the correct libfunc builder function from the selector. | ||
pub fn build<'ctx, 'this, TType, TLibfunc>( | ||
context: &'ctx Context, | ||
registry: &ProgramRegistry<TType, TLibfunc>, | ||
entry: &'this Block<'ctx>, | ||
location: Location<'ctx>, | ||
helper: &LibfuncHelper<'ctx, 'this>, | ||
metadata: &mut MetadataStorage, | ||
selector: &Bytes31ConcreteLibfunc, | ||
) -> Result<()> | ||
where | ||
TType: GenericType, | ||
TLibfunc: GenericLibfunc, | ||
<TType as GenericType>::Concrete: TypeBuilder<TType, TLibfunc, Error = CoreTypeBuilderError>, | ||
<TLibfunc as GenericLibfunc>::Concrete: LibfuncBuilder<TType, TLibfunc, Error = Error>, | ||
{ | ||
match selector { | ||
Bytes31ConcreteLibfunc::Const(info) => { | ||
build_const(context, registry, entry, location, helper, metadata, info) | ||
} | ||
Bytes31ConcreteLibfunc::ToFelt252(info) => { | ||
build_to_felt252(context, registry, entry, location, helper, metadata, info) | ||
} | ||
Bytes31ConcreteLibfunc::TryFromFelt252(info) => { | ||
build_from_felt252(context, registry, entry, location, helper, metadata, info) | ||
} | ||
} | ||
} | ||
|
||
/// Generate MLIR operations for the `bytes31_const` libfunc. | ||
pub fn build_const<'ctx, 'this, TType, TLibfunc>( | ||
context: &'ctx Context, | ||
registry: &ProgramRegistry<TType, TLibfunc>, | ||
entry: &'this Block<'ctx>, | ||
location: Location<'ctx>, | ||
helper: &LibfuncHelper<'ctx, 'this>, | ||
metadata: &mut MetadataStorage, | ||
info: &SignatureAndConstConcreteLibfunc, | ||
) -> Result<()> | ||
where | ||
TType: GenericType, | ||
TLibfunc: GenericLibfunc, | ||
<TType as GenericType>::Concrete: TypeBuilder<TType, TLibfunc, Error = CoreTypeBuilderError>, | ||
<TLibfunc as GenericLibfunc>::Concrete: LibfuncBuilder<TType, TLibfunc, Error = Error>, | ||
{ | ||
let value = &info.c; | ||
let value_ty = registry.build_type( | ||
context, | ||
helper, | ||
registry, | ||
metadata, | ||
&info.signature.branch_signatures[0].vars[0].ty, | ||
)?; | ||
|
||
let op0 = entry.append_operation(arith::constant( | ||
context, | ||
Attribute::parse(context, &format!("{value} : {value_ty}")).unwrap(), | ||
location, | ||
)); | ||
entry.append_operation(helper.br(0, &[op0.result(0)?.into()], location)); | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Generate MLIR operations for the `bytes31_to_felt252` libfunc. | ||
pub fn build_to_felt252<'ctx, 'this, TType, TLibfunc>( | ||
context: &'ctx Context, | ||
registry: &ProgramRegistry<TType, TLibfunc>, | ||
entry: &'this Block<'ctx>, | ||
location: Location<'ctx>, | ||
helper: &LibfuncHelper<'ctx, 'this>, | ||
metadata: &mut MetadataStorage, | ||
info: &SignatureOnlyConcreteLibfunc, | ||
) -> Result<()> | ||
where | ||
TType: GenericType, | ||
TLibfunc: GenericLibfunc, | ||
<TType as GenericType>::Concrete: TypeBuilder<TType, TLibfunc, Error = CoreTypeBuilderError>, | ||
<TLibfunc as GenericLibfunc>::Concrete: LibfuncBuilder<TType, TLibfunc, Error = Error>, | ||
{ | ||
let felt252_ty = registry.build_type( | ||
context, | ||
helper, | ||
registry, | ||
metadata, | ||
&info.branch_signatures()[0].vars[0].ty, | ||
)?; | ||
let value: Value = entry.argument(0)?.into(); | ||
|
||
let op = entry.append_operation(arith::extui(value, felt252_ty, location)); | ||
|
||
let result = op.result(0)?.into(); | ||
|
||
entry.append_operation(helper.br(0, &[result], location)); | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Generate MLIR operations for the `u8_from_felt252` libfunc. | ||
pub fn build_from_felt252<'ctx, 'this, TType, TLibfunc>( | ||
context: &'ctx Context, | ||
registry: &ProgramRegistry<TType, TLibfunc>, | ||
entry: &'this Block<'ctx>, | ||
location: Location<'ctx>, | ||
helper: &LibfuncHelper<'ctx, 'this>, | ||
metadata: &mut MetadataStorage, | ||
info: &SignatureOnlyConcreteLibfunc, | ||
) -> Result<()> | ||
where | ||
TType: GenericType, | ||
TLibfunc: GenericLibfunc, | ||
<TType as GenericType>::Concrete: TypeBuilder<TType, TLibfunc, Error = CoreTypeBuilderError>, | ||
<TLibfunc as GenericLibfunc>::Concrete: LibfuncBuilder<TType, TLibfunc, Error = Error>, | ||
{ | ||
let range_check: Value = entry.argument(0)?.into(); | ||
let value: Value = entry.argument(1)?.into(); | ||
|
||
let felt252_ty = registry.build_type( | ||
context, | ||
helper, | ||
registry, | ||
metadata, | ||
&info.param_signatures()[1].ty, | ||
)?; | ||
let result_ty = registry.build_type( | ||
context, | ||
helper, | ||
registry, | ||
metadata, | ||
&info.branch_signatures()[0].vars[1].ty, | ||
)?; | ||
|
||
let max_value = BigUint::from(2u32).pow(248) - 1u32; | ||
|
||
let op = entry.append_operation(arith::constant( | ||
context, | ||
Attribute::parse(context, &format!("{} : {}", max_value, felt252_ty)).unwrap(), | ||
location, | ||
)); | ||
let const_max = op.result(0)?.into(); | ||
|
||
let op = entry.append_operation(arith::cmpi( | ||
context, | ||
CmpiPredicate::Ule, | ||
value, | ||
const_max, | ||
location, | ||
)); | ||
let is_ule = op.result(0)?.into(); | ||
|
||
let block_success = helper.append_block(Block::new(&[])); | ||
let block_failure = helper.append_block(Block::new(&[])); | ||
|
||
entry.append_operation(cf::cond_br( | ||
context, | ||
is_ule, | ||
block_success, | ||
block_failure, | ||
&[], | ||
&[], | ||
location, | ||
)); | ||
|
||
let op = block_success.append_operation(arith::trunci(value, result_ty, location)); | ||
let value = op.result(0)?.into(); | ||
block_success.append_operation(helper.br(0, &[range_check, value], location)); | ||
|
||
block_failure.append_operation(helper.br(1, &[range_check], location)); | ||
|
||
Ok(()) | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use crate::utils::test::{ | ||
jit_enum, jit_panic, jit_struct, load_cairo, run_program_assert_output, | ||
}; | ||
use cairo_lang_sierra::program::Program; | ||
use lazy_static::lazy_static; | ||
use starknet_types_core::felt::Felt; | ||
|
||
lazy_static! { | ||
// todo: bytes31_const is not yet possible in current cairo version. | ||
static ref BYTES31_ROUNDTRIP: (String, Program) = load_cairo! { | ||
use core::bytes_31::{bytes31_try_from_felt252, bytes31_to_felt252}; | ||
|
||
fn run_test(value: felt252) -> felt252 { | ||
let a: bytes31 = bytes31_try_from_felt252(value).unwrap(); | ||
bytes31_to_felt252(a) | ||
} | ||
}; | ||
} | ||
|
||
#[test] | ||
fn bytes31_roundtrip() { | ||
run_program_assert_output( | ||
&BYTES31_ROUNDTRIP, | ||
"run_test", | ||
&[Felt::from(2).into()], | ||
&[jit_enum!(0, jit_struct!(Felt::from(2).into()))], | ||
); | ||
|
||
run_program_assert_output( | ||
&BYTES31_ROUNDTRIP, | ||
"run_test", | ||
&[Felt::MAX.into()], | ||
&[jit_panic!(Felt::from_bytes_be_slice( | ||
b"Option::unwrap failed." | ||
))], | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.