Skip to content

Commit 592a0ed

Browse files
authored
Merge main into dev v2.12.0 (#7951)
2 parents 7db7640 + 29c7b0a commit 592a0ed

File tree

16 files changed

+932
-603
lines changed

16 files changed

+932
-603
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bin/cairo-execute/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ cairo-lang-compiler = { path = "../../cairo-lang-compiler", version = "~2.12.0-r
1313
cairo-lang-executable = { path = "../../cairo-lang-executable", version = "~2.12.0-rc.1" }
1414
cairo-lang-execute-utils = { path = "../../cairo-lang-execute-utils", version = "~2.12.0-rc.1" }
1515
cairo-lang-runner = { path = "../../cairo-lang-runner", version = "~2.12.0-rc.1" }
16+
cairo-lang-sierra-generator = { path = "../../cairo-lang-sierra-generator", version = "~2.12.0-rc.1" }
1617
cairo-vm = { workspace = true, features = ["clap"] }
1718
clap.workspace = true
1819
num-bigint.workspace = true

crates/bin/cairo-execute/src/main.rs

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
use std::io::{self, Write};
2-
use std::path::PathBuf;
2+
use std::path::{Path, PathBuf};
33

44
use anyhow::Context;
55
use bincode::enc::write::Writer;
66
use cairo_lang_compiler::diagnostics::DiagnosticsReporter;
7-
use cairo_lang_compiler::project::check_compiler_path;
8-
use cairo_lang_executable::compile::{ExecutableConfig, compile_executable};
7+
use cairo_lang_compiler::project::{check_compiler_path, setup_project};
8+
use cairo_lang_executable::compile::{
9+
CompileExecutableResult, ExecutableConfig, compile_executable_in_prepared_db, prepare_db,
10+
};
911
use cairo_lang_executable::executable::Executable;
1012
use cairo_lang_execute_utils::{program_and_hints_from_executable, user_args_from_flags};
1113
use cairo_lang_runner::casm_run::format_for_panic;
14+
use cairo_lang_runner::profiling::{ProfilingInfo, ProfilingInfoProcessor};
1215
use cairo_lang_runner::{Arg, CairoHintProcessor};
16+
use cairo_lang_sierra_generator::replace_ids::replace_sierra_ids_in_program;
1317
use cairo_vm::cairo_run;
1418
use cairo_vm::cairo_run::{CairoRunConfig, cairo_run_program};
1519
use cairo_vm::types::layout::CairoLayoutParams;
@@ -38,13 +42,18 @@ struct Args {
3842
/// In `--build-only` this would be the executable artifact.
3943
/// In bootloader mode it will be the resulting cairo PIE file.
4044
/// In standalone mode this parameter is disallowed.
41-
#[arg(long, required_unless_present("standalone"))]
45+
#[arg(long, required_unless_present_any(["standalone", "profile"]))]
4246
output_path: Option<PathBuf>,
4347

4448
/// Whether to only run a prebuilt executable.
4549
#[arg(long, default_value_t = false, conflicts_with = "build_only")]
4650
prebuilt: bool,
4751

52+
/// The path to save the profiling result.
53+
/// Currently does not work with prebuilt executables as it requires additional debug info.
54+
#[arg(long, conflicts_with_all = ["prebuilt", "standalone"])]
55+
profile: bool,
56+
4857
#[command(flatten)]
4958
build: BuildArgs,
5059

@@ -165,30 +174,51 @@ struct ProofOutputArgs {
165174
fn main() -> anyhow::Result<()> {
166175
let args = Args::parse();
167176

168-
let executable = {
177+
let (opt_debug_data, executable) = {
169178
if args.prebuilt {
170-
serde_json::from_reader(std::fs::File::open(&args.input_path)?)
171-
.with_context(|| "Failed reading prebuilt executable.")?
179+
let executable: Executable =
180+
serde_json::from_reader(std::fs::File::open(&args.input_path)?)
181+
.with_context(|| "Failed reading prebuilt executable.")?;
182+
(None, executable)
172183
} else {
173184
// Check if args.path is a file or a directory.
174185
check_compiler_path(args.build.single_file, &args.input_path)?;
175-
let mut reporter = DiagnosticsReporter::stderr();
186+
187+
let mut diagnostics_reporter = DiagnosticsReporter::stderr();
176188
if args.build.allow_warnings {
177-
reporter = reporter.allow_warnings();
189+
diagnostics_reporter = diagnostics_reporter.allow_warnings();
178190
}
179191
if args.build.ignore_warnings {
180-
reporter = reporter.ignore_all_warnings();
192+
diagnostics_reporter = diagnostics_reporter.ignore_all_warnings();
181193
}
182-
183-
Executable::new(compile_executable(
184-
&args.input_path,
185-
args.build.executable.as_deref(),
186-
reporter,
187-
ExecutableConfig {
188-
allow_syscalls: args.build.allow_syscalls,
189-
unsafe_panic: args.build.unsafe_panic,
190-
},
191-
)?)
194+
let config = ExecutableConfig {
195+
allow_syscalls: args.build.allow_syscalls,
196+
unsafe_panic: args.build.unsafe_panic,
197+
};
198+
199+
let mut db = prepare_db(&config)?;
200+
201+
let main_crate_ids = setup_project(&mut db, Path::new(&args.input_path))?;
202+
let diagnostics_reporter = diagnostics_reporter.with_crates(&main_crate_ids);
203+
204+
let CompileExecutableResult { compiled_function, builder, debug_info } =
205+
compile_executable_in_prepared_db(
206+
&db,
207+
args.build.executable.as_deref(),
208+
main_crate_ids,
209+
diagnostics_reporter,
210+
config,
211+
)?;
212+
213+
let header_len = compiled_function
214+
.wrapper
215+
.header
216+
.iter()
217+
.map(|insn| insn.body.op_size())
218+
.sum::<usize>();
219+
220+
let executable = Executable::new(compiled_function);
221+
(Some((db, builder, debug_info, header_len)), executable)
192222
}
193223
};
194224

@@ -223,8 +253,10 @@ fn main() -> anyhow::Result<()> {
223253
None => None,
224254
};
225255

256+
let trace_enabled = args.profile || args.run.proof_outputs.trace_file.is_some();
257+
226258
let cairo_run_config = CairoRunConfig {
227-
trace_enabled: args.run.proof_outputs.trace_file.is_some(),
259+
trace_enabled,
228260
relocate_mem: args.run.proof_outputs.memory_file.is_some(),
229261
layout: args.run.layout,
230262
dynamic_layout_params,
@@ -291,6 +323,26 @@ fn main() -> anyhow::Result<()> {
291323
.write_zip_file(&file_name, true)?
292324
}
293325

326+
if args.profile {
327+
let (db, builder, debug_info, header_len) =
328+
opt_debug_data.expect("debug data should be available when profiling");
329+
330+
let trace = runner.relocated_trace.as_ref().with_context(|| "Trace not relocated.")?;
331+
let entry_point_offset = trace.first().unwrap().pc;
332+
// TODO(ilya): Compute the correct load offset for standalone mode.
333+
let load_offset = entry_point_offset + header_len;
334+
let info = ProfilingInfo::from_trace(&builder, load_offset, &Default::default(), trace);
335+
336+
let profiling_processor = ProfilingInfoProcessor::new(
337+
Some(&db),
338+
replace_sierra_ids_in_program(&db, builder.sierra_program()),
339+
debug_info.statements_locations.get_statements_functions_map_for_tests(&db),
340+
Default::default(),
341+
);
342+
let processed_profiling_info = profiling_processor.process_ex(&info, &Default::default());
343+
println!("{processed_profiling_info}");
344+
}
345+
294346
Ok(())
295347
}
296348

crates/cairo-lang-executable/src/compile.rs

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use cairo_lang_runnable_utils::builder::{
1414
CasmProgramWrapperInfo, EntryCodeConfig, RunnableBuilder,
1515
};
1616
use cairo_lang_sierra_generator::executables::find_executable_function_ids;
17-
use cairo_lang_sierra_generator::program_generator::SierraProgramWithDebug;
17+
use cairo_lang_sierra_generator::program_generator::{
18+
SierraProgramDebugInfo, SierraProgramWithDebug,
19+
};
1820
use cairo_lang_sierra_to_casm::compiler::CairoProgram;
1921
use cairo_lang_utils::{Intern, write_comma_separated};
2022
use itertools::Itertools;
@@ -62,14 +64,21 @@ pub struct ExecutableConfig {
6264
pub unsafe_panic: bool,
6365
}
6466

67+
/// Represents the output of compiling an executable.
68+
///
69+
/// Includes the `CompiledFunction` along with supplementary objects useful for profiling.
70+
pub struct CompileExecutableResult {
71+
/// The compiled function.
72+
pub compiled_function: CompiledFunction,
73+
/// A runnable builder with the program corresponding to the compiled function.
74+
pub builder: RunnableBuilder,
75+
/// The debug info for the sierra program in the builder.
76+
pub debug_info: SierraProgramDebugInfo,
77+
}
78+
6579
/// Compile the function given by path.
6680
/// Errors if there is ambiguity.
67-
pub fn compile_executable(
68-
path: &Path,
69-
executable_path: Option<&str>,
70-
diagnostics_reporter: DiagnosticsReporter<'_>,
71-
config: ExecutableConfig,
72-
) -> Result<CompiledFunction> {
81+
pub fn prepare_db(config: &ExecutableConfig) -> Result<RootDatabase> {
7382
let mut builder = RootDatabase::builder();
7483
builder
7584
.skip_auto_withdraw_gas()
@@ -80,7 +89,18 @@ pub fn compile_executable(
8089
builder.with_unsafe_panic();
8190
}
8291

83-
let mut db = builder.build()?;
92+
builder.build()
93+
}
94+
95+
/// Compile the function given by path.
96+
/// Errors if there is ambiguity.
97+
pub fn compile_executable(
98+
path: &Path,
99+
executable_path: Option<&str>,
100+
diagnostics_reporter: DiagnosticsReporter<'_>,
101+
config: ExecutableConfig,
102+
) -> Result<CompileExecutableResult> {
103+
let mut db = prepare_db(&config)?;
84104

85105
let main_crate_ids = setup_project(&mut db, Path::new(&path))?;
86106
let diagnostics_reporter = diagnostics_reporter.with_crates(&main_crate_ids);
@@ -103,7 +123,7 @@ pub fn compile_executable_in_prepared_db(
103123
main_crate_ids: Vec<CrateId>,
104124
mut diagnostics_reporter: DiagnosticsReporter<'_>,
105125
config: ExecutableConfig,
106-
) -> Result<CompiledFunction> {
126+
) -> Result<CompileExecutableResult> {
107127
let context = DbWarmupContext::new();
108128
context.ensure_diagnostics(db, &mut diagnostics_reporter)?;
109129

@@ -183,7 +203,7 @@ pub fn compile_executable_function_in_prepared_db(
183203
executable: ConcreteFunctionWithBodyId,
184204
config: ExecutableConfig,
185205
context: DbWarmupContext,
186-
) -> Result<CompiledFunction> {
206+
) -> Result<CompileExecutableResult> {
187207
let SierraProgramWithDebug { program: sierra_program, debug_info } = Arc::unwrap_or_clone(
188208
get_sierra_program_for_functions(db, vec![executable], context)
189209
.ok()
@@ -228,5 +248,6 @@ pub fn compile_executable_function_in_prepared_db(
228248
let allow_unsound = config.allow_syscalls;
229249
let wrapper = builder
230250
.create_wrapper_info(&executable_func, EntryCodeConfig::executable(allow_unsound))?;
231-
Ok(CompiledFunction { program: builder.casm_program().clone(), wrapper })
251+
let compiled_function = CompiledFunction { program: builder.casm_program().clone(), wrapper };
252+
Ok(CompileExecutableResult { compiled_function, builder, debug_info })
232253
}

crates/cairo-lang-executable/src/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl TestFileRunner for CompileExecutableTestRunner {
7979
DiagnosticsReporter::stderr().with_crates(&[test_module.crate_id]),
8080
Default::default(),
8181
)
82-
.map(|compiled| compiled.to_string())
82+
.map(|compiled| compiled.compiled_function.to_string())
8383
.unwrap_or_else(|e| e.to_string());
8484
let error = verify_diagnostics_expectation(args, &semantic_diagnostics);
8585
TestRunnerResult {

crates/cairo-lang-lowering/src/borrow_check/test_data/closure

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,44 +110,58 @@ error: Capture of mutable variables in a closure is not supported
110110

111111
//! > ==========================================================================
112112

113-
//! > invalidated capture immutable variable
113+
//! > Use of captured var.
114114

115115
//! > test_runner_name
116116
test_borrow_check
117117

118118
//! > function
119119
fn foo(a: S) {
120-
|b: u32| {
121-
let _ = a.a + b;
120+
|| {
121+
use_s(a)
122122
};
123+
124+
// TODO(ilya): Consider adding automatic destructuring of the closure before the following line
123125
let _ = a.a;
124126
}
125127

126128
//! > function_name
127129
foo
128130

129131
//! > module_code
132+
#[derive(Drop)]
130133
struct S {
131134
a: u32,
132135
}
133136

137+
extern fn use_s(s: S) nopanic;
138+
134139
//! > semantic_diagnostics
135140

136141
//! > lowering_diagnostics
142+
error: Variable was previously moved.
143+
--> lib.cairo:13:13
144+
let _ = a.a;
145+
^^^
146+
note: variable was previously used here:
147+
--> lib.cairo:9:15
148+
use_s(a)
149+
^
150+
note: Trait has no implementation in context: core::traits::Copy::<test::S>.
137151

138152
//! > lowering
139153
Parameters: v0: test::S
140154
blk0 (root):
141155
Statements:
142-
(v1: core::integer::u32) <- struct_destructure(v0{`a.a`})
143-
(v2: {[email protected]:5:5: 5:13}) <- struct_construct(v1{`a.a`})
156+
(v1: {[email protected]:8:5: 8:7}) <- struct_construct(v0{`a`})
157+
(v2: core::integer::u32) <- struct_destructure(v0{`a.a`})
144158
(v3: ()) <- struct_construct()
145159
End:
146160
Return(v3)
147161

148162
//! > ==========================================================================
149163

150-
//! > capture use after invalidatian.
164+
//! > Use of captured mutable variable.
151165

152166
//! > test_runner_name
153167
test_borrow_check
@@ -185,29 +199,37 @@ error: Capture of mutable variables in a closure is not supported
185199
test_borrow_check
186200

187201
//! > function
188-
fn foo(mut a: Array<u32>) {
202+
fn foo(a: Array<u32>) {
189203
let f = |_b: u32| {
190204
let _ = a.len();
191205
};
192-
a.append(0);
193-
use_f(f)
206+
// Since only a snapshot of `a` is capture, we can use it while it is captured.
207+
use_value(a);
208+
209+
use_value(f);
194210
}
195211

196212
//! > function_name
197213
foo
198214

199215
//! > module_code
200-
extern fn use_f<T>(f: T) nopanic;
216+
extern fn use_value<T>(f: T) nopanic;
201217

202218
//! > semantic_diagnostics
203-
error: Capture of mutable variables in a closure is not supported
204-
--> lib.cairo:4:17
205-
let _ = a.len();
206-
^
207219

208220
//! > lowering_diagnostics
209221

210222
//! > lowering
223+
Parameters: v0: core::array::Array::<core::integer::u32>
224+
blk0 (root):
225+
Statements:
226+
(v1: core::array::Array::<core::integer::u32>, v2: @core::array::Array::<core::integer::u32>) <- snapshot(v0{`a`})
227+
(v3: {[email protected]:3:13: 3:22}) <- struct_construct(v2{`|_b: u32| { let _ = a.len(); }`})
228+
() <- test::use_value::<core::array::Array::<core::integer::u32>>(v1{`a`})
229+
() <- test::use_value::<{[email protected]:3:13: 3:22}>(v3{`f`})
230+
(v4: ()) <- struct_construct()
231+
End:
232+
Return(v4)
211233

212234
//! > ==========================================================================
213235

0 commit comments

Comments
 (0)