From fdac014932248258b2f43c8debee6c5289c70886 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Thu, 19 Jun 2025 17:53:26 -0300 Subject: [PATCH 1/4] Remove ignores --- docs/execution_walkthrough.md | 22 +++++++++++----------- docs/gas_builtin_accounting.md | 6 +++--- docs/implementing_libfuncs.md | 4 ++-- docs/overview.md | 6 +++--- src/metadata/debug_utils.rs | 2 +- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/execution_walkthrough.md b/docs/execution_walkthrough.md index d5b78d26f9..1a884cd46b 100644 --- a/docs/execution_walkthrough.md +++ b/docs/execution_walkthrough.md @@ -2,7 +2,7 @@ Given the following Cairo program: -```rust,ignore +```rust // This is the cairo program. It just adds two numbers together and returns the // result in an enum whose variant is selected using the result's parity. enum Parity { @@ -22,7 +22,7 @@ fn run(lhs: u128, rhs: u128) -> Parity { Let's see how it is executed. We start with the following Rust code: -```rust,ignore +```rust let program = get_sierra_program(); // The result of the `cairo-compile` program. let module = get_native_module(&program); // This compiles the Sierra program to // MLIR (not covered here). @@ -34,7 +34,7 @@ Given a compiled Cairo program in an MLIR module, once it is lowered to the LLVM ### Using the JIT executor If we decide to use the JIT executor we just create the jit runner and we're done. -```rust,ignore +```rust let program = get_sierra_program(); let module = get_native_module(&program); @@ -47,7 +47,7 @@ let engine = JitNativeExecutor::from_native_module(module, OptLevel::Default); ### Using the AOT executor Preparing the AOT executor is more complicated since we need to compile it into a shared library and load it from disk. -```rust,ignore +```rust let program = get_sierra_program(); let module = get_native_module(&program); @@ -61,7 +61,7 @@ You can use caches to keep the compiled programs in memory or disk and reuse the Adding programs to the program cache involves steps not covered here, but once they're inserted you can get executors like this: -```rust,ignore +```rust let engine = program_cache.get(key).expect("program not found"); ``` @@ -74,7 +74,7 @@ In a future we may be able to implement compile-time trampolines for known progr Now we need to find the function id: -```rust,ignore +```rust let program = get_sierra_program(); // The utility function needs the symbol of the entry point, which is built as @@ -88,7 +88,7 @@ let function_id = find_function_id(&program, "program::program::main(f0)"); The arguments must be placed in a list of `JitValue` instances. The builtins should be ignored since they are filled in automatically. The only builtins required are the `GasBuiltin` and `System` (aka. the syscall handler). They are only mandatory when required by the program itself. -```rust,ignore +```rust let engine = get_execution_engine(); // This creates the execution engine (covered before). let args = [ @@ -101,7 +101,7 @@ let args = [ Finally we can invoke the program like this: -```rust,ignore +```rust let engine = get_execution_engine(); let function_id = find_function_id(&program, "program::program::main(f0)"); @@ -127,7 +127,7 @@ println!("Builtin stats: {:?}", execution_result.builtin_stats); Running the code above should print the following: -```rust,ignore +```rust Remaining gas: None Return value: Enum { tag: 0, @@ -157,7 +157,7 @@ Builtin stats: BuiltinStats { bitwise: 1, ec_op: 0, range_check: 1, pedersen: 0, ### Contracts Contracts always have the same interface, therefore they have an alternative to `invoke_dynamic` called `invoke_contract_dynamic`. -```rust,ignore +```rust fn(Span) -> PanicResult>; ``` @@ -165,7 +165,7 @@ This wrapper will attempt to deserialize the real contract arguments from the sp If the example program had the same interface as a contract (a span of felts) then it'd be invoked like this: -```rust,ignore +```rust let engine = get_execution_engine(); let function_id = find_function_id(&program, "program::program::main(f0)"); diff --git a/docs/gas_builtin_accounting.md b/docs/gas_builtin_accounting.md index 8f9cccb3e8..0aa3693a46 100644 --- a/docs/gas_builtin_accounting.md +++ b/docs/gas_builtin_accounting.md @@ -52,7 +52,7 @@ amount being withdrawn. ### Example Let's illustrate this with a simple example using the following Cairo 1 code: -```rust,ignore +```rust fn run_test() { let mut i: u8 = 0; let mut val = 0; @@ -131,7 +131,7 @@ returned by the function. This is accomplished when [parsing the return values](https://github.com/lambdaclass/cairo_native/blob/65face8194054b7ed396a34a60e7b1595197543a/src/executor.rs#L286) from the function call: -```rust,ignore +```rust ... for type_id in &function_signature.ret_types { let type_info = registry.get_type(type_id).unwrap(); @@ -174,7 +174,7 @@ called from within the program. ### Example Let us consider the following Cairo program which uses the `pedersen` builtin: -```rust,ignore +```rust use core::integer::bitwise; use core::pedersen::pedersen; diff --git a/docs/implementing_libfuncs.md b/docs/implementing_libfuncs.md index aaef8d4d20..fc93647088 100644 --- a/docs/implementing_libfuncs.md +++ b/docs/implementing_libfuncs.md @@ -64,7 +64,7 @@ Libfuncs are implemented under `src/libfuncs.rs` and Using the `src/libfuncs/felt252.rs` libfuncs as a aid: -```rust,ignore +```rust /// Select and call the correct libfunc builder function from the selector. pub fn build<'ctx, 'this>( context: &'ctx Context, @@ -100,7 +100,7 @@ the `src/libfuncs.rs` match statement. ### Example libfunc implementation: u8_to_felt252 An example libfunc, converting a u8 to a felt252, extensively commented: -```rust,ignore +```rust /// Generate MLIR operations for the `u8_to_felt252` libfunc. pub fn build_to_felt252<'ctx, 'this>( // The Context from MLIR, this is like the heart of the MLIR API, its required to create most stuff like types. diff --git a/docs/overview.md b/docs/overview.md index 15409d79b0..b329518480 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -151,7 +151,7 @@ lowering to LLVM. compiled sierra programs from an entrypoint. Programs and JIT states can be cached in contexts where their execution will be done multiple times. -```rust,ignore +```rust use starknet_types_core::felt::Felt; use cairo_native::context::NativeContext; use cairo_native::executor::JitNativeExecutor; @@ -196,7 +196,7 @@ execute a program using the JIT. Example code to run a program: -```rust,ignore +```rust use starknet_types_core::felt::Felt; use cairo_native::context::NativeContext; use cairo_native::executor::NativeExecutor; @@ -239,7 +239,7 @@ fn main() { Example code to run a Starknet contract: -```rust,ignore +```rust use starknet_types_core::felt::Felt; use cairo_lang_compiler::CompilerConfig; use cairo_lang_starknet::contract_class::compile_path; diff --git a/src/metadata/debug_utils.rs b/src/metadata/debug_utils.rs index 2872aef07c..ee218cd0e7 100644 --- a/src/metadata/debug_utils.rs +++ b/src/metadata/debug_utils.rs @@ -4,7 +4,7 @@ //! //! ## Example //! -//! ```rust,ignore +//! ```rust //! # use cairo_lang_sierra::{ //! # extensions::{ //! # core::{CoreLibfunc, CoreType}, From cd44e7ccd3089106e8a88a4a3f1d22d1062a74c5 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Mon, 23 Jun 2025 12:36:32 -0300 Subject: [PATCH 2/4] Remove only necessary ignores --- docs/compilation_walkthrough.md | 2 +- docs/execution_walkthrough.md | 22 ++++---- docs/gas_builtin_accounting.md | 6 +-- docs/implementing_libfuncs.md | 23 ++++++--- docs/overview.md | 91 ++++++++++++++++++--------------- src/metadata/debug_utils.rs | 2 +- 6 files changed, 82 insertions(+), 64 deletions(-) diff --git a/docs/compilation_walkthrough.md b/docs/compilation_walkthrough.md index 46a60705da..99a917fc1b 100644 --- a/docs/compilation_walkthrough.md +++ b/docs/compilation_walkthrough.md @@ -189,7 +189,7 @@ LLVM_InitializeAllAsmParsers(); After that we create a LLVM context, and pass it along the module to the `mlirTranslateModuleToLLVMIR` method: -```rust ,ignore +```rust,ignore let llvm_module = mlirTranslateModuleToLLVMIR(mlir_module_op, llvm_context); ``` diff --git a/docs/execution_walkthrough.md b/docs/execution_walkthrough.md index 1a884cd46b..d5b78d26f9 100644 --- a/docs/execution_walkthrough.md +++ b/docs/execution_walkthrough.md @@ -2,7 +2,7 @@ Given the following Cairo program: -```rust +```rust,ignore // This is the cairo program. It just adds two numbers together and returns the // result in an enum whose variant is selected using the result's parity. enum Parity { @@ -22,7 +22,7 @@ fn run(lhs: u128, rhs: u128) -> Parity { Let's see how it is executed. We start with the following Rust code: -```rust +```rust,ignore let program = get_sierra_program(); // The result of the `cairo-compile` program. let module = get_native_module(&program); // This compiles the Sierra program to // MLIR (not covered here). @@ -34,7 +34,7 @@ Given a compiled Cairo program in an MLIR module, once it is lowered to the LLVM ### Using the JIT executor If we decide to use the JIT executor we just create the jit runner and we're done. -```rust +```rust,ignore let program = get_sierra_program(); let module = get_native_module(&program); @@ -47,7 +47,7 @@ let engine = JitNativeExecutor::from_native_module(module, OptLevel::Default); ### Using the AOT executor Preparing the AOT executor is more complicated since we need to compile it into a shared library and load it from disk. -```rust +```rust,ignore let program = get_sierra_program(); let module = get_native_module(&program); @@ -61,7 +61,7 @@ You can use caches to keep the compiled programs in memory or disk and reuse the Adding programs to the program cache involves steps not covered here, but once they're inserted you can get executors like this: -```rust +```rust,ignore let engine = program_cache.get(key).expect("program not found"); ``` @@ -74,7 +74,7 @@ In a future we may be able to implement compile-time trampolines for known progr Now we need to find the function id: -```rust +```rust,ignore let program = get_sierra_program(); // The utility function needs the symbol of the entry point, which is built as @@ -88,7 +88,7 @@ let function_id = find_function_id(&program, "program::program::main(f0)"); The arguments must be placed in a list of `JitValue` instances. The builtins should be ignored since they are filled in automatically. The only builtins required are the `GasBuiltin` and `System` (aka. the syscall handler). They are only mandatory when required by the program itself. -```rust +```rust,ignore let engine = get_execution_engine(); // This creates the execution engine (covered before). let args = [ @@ -101,7 +101,7 @@ let args = [ Finally we can invoke the program like this: -```rust +```rust,ignore let engine = get_execution_engine(); let function_id = find_function_id(&program, "program::program::main(f0)"); @@ -127,7 +127,7 @@ println!("Builtin stats: {:?}", execution_result.builtin_stats); Running the code above should print the following: -```rust +```rust,ignore Remaining gas: None Return value: Enum { tag: 0, @@ -157,7 +157,7 @@ Builtin stats: BuiltinStats { bitwise: 1, ec_op: 0, range_check: 1, pedersen: 0, ### Contracts Contracts always have the same interface, therefore they have an alternative to `invoke_dynamic` called `invoke_contract_dynamic`. -```rust +```rust,ignore fn(Span) -> PanicResult>; ``` @@ -165,7 +165,7 @@ This wrapper will attempt to deserialize the real contract arguments from the sp If the example program had the same interface as a contract (a span of felts) then it'd be invoked like this: -```rust +```rust,ignore let engine = get_execution_engine(); let function_id = find_function_id(&program, "program::program::main(f0)"); diff --git a/docs/gas_builtin_accounting.md b/docs/gas_builtin_accounting.md index 0aa3693a46..8f9cccb3e8 100644 --- a/docs/gas_builtin_accounting.md +++ b/docs/gas_builtin_accounting.md @@ -52,7 +52,7 @@ amount being withdrawn. ### Example Let's illustrate this with a simple example using the following Cairo 1 code: -```rust +```rust,ignore fn run_test() { let mut i: u8 = 0; let mut val = 0; @@ -131,7 +131,7 @@ returned by the function. This is accomplished when [parsing the return values](https://github.com/lambdaclass/cairo_native/blob/65face8194054b7ed396a34a60e7b1595197543a/src/executor.rs#L286) from the function call: -```rust +```rust,ignore ... for type_id in &function_signature.ret_types { let type_info = registry.get_type(type_id).unwrap(); @@ -174,7 +174,7 @@ called from within the program. ### Example Let us consider the following Cairo program which uses the `pedersen` builtin: -```rust +```rust,ignore use core::integer::bitwise; use core::pedersen::pedersen; diff --git a/docs/implementing_libfuncs.md b/docs/implementing_libfuncs.md index fc93647088..ae167e8e40 100644 --- a/docs/implementing_libfuncs.md +++ b/docs/implementing_libfuncs.md @@ -64,7 +64,19 @@ Libfuncs are implemented under `src/libfuncs.rs` and Using the `src/libfuncs/felt252.rs` libfuncs as a aid: -```rust +```rust,ignore +use melior::Context; +use melior::ir::Block; +use melior::ir::Location; +use cairo_lang_sierra::{ + extensions::{ + core::{CoreLibfunc, CoreType}, + felt252::Felt252Concrete, + }, + program_registry::ProgramRegistry, +}; +use cairo_native::metadata::MetadataStorage; + /// Select and call the correct libfunc builder function from the selector. pub fn build<'ctx, 'this>( context: &'ctx Context, @@ -100,7 +112,7 @@ the `src/libfuncs.rs` match statement. ### Example libfunc implementation: u8_to_felt252 An example libfunc, converting a u8 to a felt252, extensively commented: -```rust +```rust,ignore /// Generate MLIR operations for the `u8_to_felt252` libfunc. pub fn build_to_felt252<'ctx, 'this>( // The Context from MLIR, this is like the heart of the MLIR API, its required to create most stuff like types. @@ -125,20 +137,19 @@ pub fn build_to_felt252<'ctx, 'this>( let felt252_ty = registry.build_type( context, helper, - registry, metadata, &info.branch_signatures()[0].vars[0].ty, )?; // Retrieve the first argument passed to this library function, in this case its the u8 value we need to convert. - let value: Value = entry.argument(0)?.into(); + let value: Value = entry.arg(0)?; // We create a "extui" operation from the "arith" dialect, which basically // zero extends the value to have the same bits as the given type. - let result = entry.append_op_result(arith::extui(value, felt252_ty, location))?; + let result = entry.extui(value, felt252_ty, location)?; // Using the helper argument, append the branching operation to the next statement, passing result as our output variable. - entry.append_operation(helper.br(0, &[result], location)); + helper.br(0, &[result], location); Ok(()) } diff --git a/docs/overview.md b/docs/overview.md index b329518480..9d438fc84b 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -152,40 +152,47 @@ compiled sierra programs from an entrypoint. Programs and JIT states can be cached in contexts where their execution will be done multiple times. ```rust +use cairo_native::{ + context::NativeContext, executor::JitNativeExecutor, utils::cairo_to_sierra, Value, +}; use starknet_types_core::felt::Felt; -use cairo_native::context::NativeContext; -use cairo_native::executor::JitNativeExecutor; -use cairo_native::values::JitValue; use std::path::Path; -let program_path = Path::new("programs/examples/hello.cairo"); -// Compile the cairo program to sierra. -let sierra_program = cairo_native::utils::cairo_to_sierra(program_path); +fn main() { + let program_path = Path::new("programs/examples/hello.cairo"); -// Instantiate a Cairo Native MLIR context. This data structure is responsible for the MLIR -// initialization and compilation of sierra programs into a MLIR module. -let native_context = NativeContext::new(); + // Instantiate a Cairo Native MLIR context. This data structure is responsible for the MLIR + // initialization and compilation of sierra programs into a MLIR module. + let native_context = NativeContext::new(); + + // Compile the cairo program to sierra. + let sierra_program = cairo_to_sierra(program_path).unwrap(); -// Compile the sierra program into a MLIR module. -let native_program = native_context.compile(&sierra_program, None).unwrap(); + // Compile the sierra program into a MLIR module. + let native_program = native_context + .compile(&sierra_program, false, Some(Default::default()), None) + .unwrap(); -// The parameters of the entry point. -let params = &[JitValue::Felt252(Felt::from_bytes_be_slice(b"user"))]; + // The parameters of the entry point. + let params = &[Value::Felt252(Felt::from_bytes_be_slice(b"user"))]; -// Find the entry point id by its name. -let entry_point = "hello::hello::greet"; -let entry_point_id = cairo_native::utils::find_function_id(&sierra_program, entry_point); + // Find the entry point id by its name. + let entry_point = "hello::hello::greet"; + let entry_point_id = cairo_native::utils::find_function_id(&sierra_program, entry_point) + .expect("entry point not found"); -// Instantiate the executor. -let native_executor = JitNativeExecutor::from_native_module(native_program, Default::default()); + // Instantiate the executor. + let native_executor = + JitNativeExecutor::from_native_module(native_program, Default::default()).unwrap(); -// Execute the program. -let result = native_executor - .invoke_dynamic(entry_point_id, params, None) - .unwrap(); + // Execute the program. + let result = native_executor + .invoke_dynamic(entry_point_id, params, None) + .unwrap(); -println!("Cairo program was compiled and executed successfully."); -println!("{:?}", result); + println!("Cairo program was compiled and executed successfully."); + println!("{:?}", result); +} ``` ## Running a Cairo program @@ -197,41 +204,41 @@ execute a program using the JIT. Example code to run a program: ```rust -use starknet_types_core::felt::Felt; -use cairo_native::context::NativeContext; -use cairo_native::executor::NativeExecutor; -use cairo_native::values::JitValue; +use cairo_native::{ + context::NativeContext, executor::JitNativeExecutor, utils::find_entry_point, Value, +}; use std::path::Path; +use tracing_subscriber::{EnvFilter, FmtSubscriber}; fn main() { - let program_path = Path::new("programs/examples/hello.cairo"); + let program_path = Path::new("programs/echo.cairo"); + // Compile the cairo program to sierra. - let sierra_program = cairo_native::utils::cairo_to_sierra(program_path); + let sierra_program = cairo_native::utils::cairo_to_sierra(program_path).unwrap(); // Instantiate a Cairo Native MLIR context. This data structure is responsible for the MLIR // initialization and compilation of sierra programs into a MLIR module. let native_context = NativeContext::new(); // Compile the sierra program into a MLIR module. - let native_program = native_context.compile(&sierra_program).unwrap(); - - // The parameters of the entry point. - let params = &[JitValue::Felt252(Felt::from_bytes_be_slice(b"user"))]; + let native_program = native_context + .compile(&sierra_program, false, Some(Default::default()), None) + .unwrap(); // Find the entry point id by its name. - let entry_point = "hello::hello::greet"; - let entry_point_id = cairo_native::utils::find_function_id(&sierra_program, entry_point); + let entry_point_fn = find_entry_point(&sierra_program, "echo::echo::main").unwrap(); + let fn_id = &entry_point_fn.id; // Instantiate the executor. - let native_executor = NativeExecutor::new(native_program); + let native_executor = + JitNativeExecutor::from_native_module(native_program, Default::default()).unwrap(); // Execute the program. - let result = native_executor - .execute(entry_point_id, params, None) - .unwrap(); + let output = native_executor.invoke_dynamic(fn_id, &[Value::Felt252(1.into())], None); + println!(); println!("Cairo program was compiled and executed successfully."); - println!("{:?}", result); + println!("{output:#?}"); } ``` @@ -239,7 +246,7 @@ fn main() { Example code to run a Starknet contract: -```rust +```rust,ignore use starknet_types_core::felt::Felt; use cairo_lang_compiler::CompilerConfig; use cairo_lang_starknet::contract_class::compile_path; diff --git a/src/metadata/debug_utils.rs b/src/metadata/debug_utils.rs index ee218cd0e7..2872aef07c 100644 --- a/src/metadata/debug_utils.rs +++ b/src/metadata/debug_utils.rs @@ -4,7 +4,7 @@ //! //! ## Example //! -//! ```rust +//! ```rust,ignore //! # use cairo_lang_sierra::{ //! # extensions::{ //! # core::{CoreLibfunc, CoreType}, From bcdb2a4a6d73252cbbfc64082b2e465e89fa542a Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Mon, 23 Jun 2025 12:38:27 -0300 Subject: [PATCH 3/4] Remove unnecessary imports --- docs/implementing_libfuncs.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/docs/implementing_libfuncs.md b/docs/implementing_libfuncs.md index ae167e8e40..15b6a7cef2 100644 --- a/docs/implementing_libfuncs.md +++ b/docs/implementing_libfuncs.md @@ -65,18 +65,6 @@ Libfuncs are implemented under `src/libfuncs.rs` and Using the `src/libfuncs/felt252.rs` libfuncs as a aid: ```rust,ignore -use melior::Context; -use melior::ir::Block; -use melior::ir::Location; -use cairo_lang_sierra::{ - extensions::{ - core::{CoreLibfunc, CoreType}, - felt252::Felt252Concrete, - }, - program_registry::ProgramRegistry, -}; -use cairo_native::metadata::MetadataStorage; - /// Select and call the correct libfunc builder function from the selector. pub fn build<'ctx, 'this>( context: &'ctx Context, From 17a216b0e1e1920db5531f516f873584e8389932 Mon Sep 17 00:00:00 2001 From: Diego Civini Date: Mon, 23 Jun 2025 17:57:25 -0300 Subject: [PATCH 4/4] Revert PR unrelated changes --- docs/implementing_libfuncs.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/implementing_libfuncs.md b/docs/implementing_libfuncs.md index 15b6a7cef2..aaef8d4d20 100644 --- a/docs/implementing_libfuncs.md +++ b/docs/implementing_libfuncs.md @@ -125,19 +125,20 @@ pub fn build_to_felt252<'ctx, 'this>( let felt252_ty = registry.build_type( context, helper, + registry, metadata, &info.branch_signatures()[0].vars[0].ty, )?; // Retrieve the first argument passed to this library function, in this case its the u8 value we need to convert. - let value: Value = entry.arg(0)?; + let value: Value = entry.argument(0)?.into(); // We create a "extui" operation from the "arith" dialect, which basically // zero extends the value to have the same bits as the given type. - let result = entry.extui(value, felt252_ty, location)?; + let result = entry.append_op_result(arith::extui(value, felt252_ty, location))?; // Using the helper argument, append the branching operation to the next statement, passing result as our output variable. - helper.br(0, &[result], location); + entry.append_operation(helper.br(0, &[result], location)); Ok(()) }