Skip to content

Commit 2e496a0

Browse files
(optimization): Reboxing also applied on Box of snapshots
1 parent 04c6b94 commit 2e496a0

File tree

4 files changed

+120
-32
lines changed

4 files changed

+120
-32
lines changed

crates/cairo-lang-lowering/src/optimizations/reboxing.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ use std::rc::Rc;
77
use cairo_lang_filesystem::flag::flag_future_sierra;
88
use cairo_lang_semantic::helper::ModuleHelper;
99
use cairo_lang_semantic::items::structure::StructSemantic;
10-
use cairo_lang_semantic::types::{TypesSemantic, peel_snapshots};
10+
use cairo_lang_semantic::types::{TypesSemantic, peel_snapshots, wrap_in_snapshots};
1111
use cairo_lang_semantic::{ConcreteTypeId, GenericArgumentId, TypeLongId};
1212
use cairo_lang_utils::ordered_hash_map::{Entry, OrderedHashMap};
1313
use cairo_lang_utils::ordered_hash_set::OrderedHashSet;
14+
use itertools::Itertools;
1415
use salsa::Database;
1516

1617
use crate::borrow_check::analysis::StatementLocation;
@@ -257,22 +258,17 @@ fn create_struct_boxed_deconstruct_call<'db>(
257258
}
258259
let (n_snapshots, struct_ty) = peel_snapshots(db, *inner_ty);
259260

260-
// TODO(eytan-starkware): Support snapshots of structs in reboxing optimization.
261-
// Currently we give up if the struct is wrapped in snapshots.
262-
if n_snapshots > 0 {
263-
trace!("Skipping reboxing for snapshotted struct (n_snapshots={})", n_snapshots);
264-
return None;
265-
}
266-
267-
// Extract member types from struct or tuple
261+
trace!("Extracted struct or tuple type: {:?}", struct_ty);
268262
let member_types = match struct_ty {
269263
TypeLongId::Concrete(ConcreteTypeId::Struct(struct_id)) => db
270264
.concrete_struct_members(struct_id)
271265
.ok()?
272266
.iter()
273-
.map(|(_, member)| member.ty)
274-
.collect::<Vec<_>>(),
275-
TypeLongId::Tuple(inner_types) => inner_types,
267+
.map(|(_, member)| wrap_in_snapshots(db, member.ty, n_snapshots))
268+
.collect_vec(),
269+
TypeLongId::Tuple(inner_types) => {
270+
inner_types.into_iter().map(|ty| wrap_in_snapshots(db, ty, n_snapshots)).collect()
271+
}
276272
_ => {
277273
trace!("Unsupported type for reboxing: {:?}", struct_ty);
278274
return None;

crates/cairo-lang-lowering/src/optimizations/test_data/reboxing

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ blk0 (root):
215215
Statements:
216216
(v1: @test::Data) <- core::box::unbox::<@test::Data>(v0)
217217
(v2: @test::NonCopy, v3: @core::felt252) <- struct_destructure(v1)
218-
(v4: core::box::Box::<@test::NonCopy>) <- core::box::into_box::<@test::NonCopy>(v2)
218+
(v4: core::box::Box::<@test::NonCopy>, v5: core::box::Box::<@core::felt252>) <- struct_destructure(v0)
219219
End:
220220
Return(v4)
221221

@@ -690,3 +690,64 @@ Statements:
690690
(v5: (core::box::Box::<core::felt252>, test::NonDrop)) <- struct_construct(v4, v3)
691691
End:
692692
Return(v5)
693+
694+
//! > ==========================================================================
695+
696+
//! > Test reboxing with snapshot of non-drop struct and member
697+
698+
//! > test_runner_name
699+
test_reboxing_analysis
700+
701+
//! > function_name
702+
main
703+
704+
//! > module_code
705+
use core::box::BoxTrait;
706+
707+
#[derive(Copy)]
708+
struct NonDrop {
709+
b: felt252,
710+
}
711+
712+
#[derive(Copy)]
713+
struct A {
714+
a: felt252,
715+
non_drop: NonDrop,
716+
}
717+
718+
//! > function_code
719+
fn main(a: Box<@A>) -> (Box<@felt252>, @NonDrop) {
720+
let a = a.unbox();
721+
(BoxTrait::new(a.a), a.non_drop)
722+
}
723+
724+
//! > semantic_diagnostics
725+
726+
//! > lowering_diagnostics
727+
728+
//! > candidates
729+
v4
730+
731+
//! > before
732+
Parameters: v0: core::box::Box::<@test::A>
733+
blk0 (root):
734+
Statements:
735+
(v1: @test::A) <- core::box::unbox::<@test::A>(v0)
736+
(v2: @core::felt252, v3: @test::NonDrop) <- struct_destructure(v1)
737+
(v4: core::box::Box::<@core::felt252>) <- core::box::into_box::<@core::felt252>(v2)
738+
(v5: @core::felt252, v6: @test::NonDrop) <- struct_destructure(v1)
739+
(v7: (core::box::Box::<@core::felt252>, @test::NonDrop)) <- struct_construct(v4, v6)
740+
End:
741+
Return(v7)
742+
743+
//! > after
744+
Parameters: v0: core::box::Box::<@test::A>
745+
blk0 (root):
746+
Statements:
747+
(v1: @test::A) <- core::box::unbox::<@test::A>(v0)
748+
(v2: @core::felt252, v3: @test::NonDrop) <- struct_destructure(v1)
749+
(v4: core::box::Box::<@core::felt252>, v8: core::box::Box::<@test::NonDrop>) <- struct_destructure(v0)
750+
(v5: @core::felt252, v6: @test::NonDrop) <- struct_destructure(v1)
751+
(v7: (core::box::Box::<@core::felt252>, @test::NonDrop)) <- struct_construct(v4, v6)
752+
End:
753+
Return(v7)

crates/cairo-lang-sierra-generator/src/function_generator_test_data/struct

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,15 @@ struct A {
118118

119119
//! > lowering_diagnostics
120120

121-
//! > TODO(eytan-starkware): Rebox on non-copy structs.
122-
123121
//! > sierra_code
124122
label_test::foo::0:
125-
unbox<Snapshot<test::A>>([0]) -> ([1])
126-
store_temp<Snapshot<test::A>>([1]) -> ([1])
127-
struct_snapshot_deconstruct<test::A>([1]) -> ([2], [3])
128-
drop<Snapshot<Array<felt252>>>([3]) -> ()
129-
into_box<Snapshot<Array<felt252>>>([2]) -> ([4])
130-
return([4])
123+
dup<Box<Snapshot<test::A>>>([0]) -> ([0], [1])
124+
unbox<Snapshot<test::A>>([1]) -> ([2])
125+
drop<Snapshot<test::A>>([2]) -> ()
126+
struct_boxed_deconstruct<Snapshot<test::A>>([0]) -> ([3], [4])
127+
drop<Box<Snapshot<Array<felt252>>>>([4]) -> ()
128+
store_temp<Box<Snapshot<Array<felt252>>>>([3]) -> ([3])
129+
return([3])
131130

132131
//! > ==========================================================================
133132

@@ -155,15 +154,48 @@ struct A {
155154

156155
//! > lowering_diagnostics
157156

158-
//! > TODO(eytan-starkware): We want reboxing to apply to sierra in the future,
157+
//! > sierra_code
158+
label_test::foo::0:
159+
dup<Box<Snapshot<test::A>>>([0]) -> ([0], [1])
160+
unbox<Snapshot<test::A>>([1]) -> ([2])
161+
drop<Snapshot<test::A>>([2]) -> ()
162+
struct_boxed_deconstruct<Snapshot<test::A>>([0]) -> ([3], [4])
163+
drop<Box<Snapshot<Array<felt252>>>>([4]) -> ()
164+
store_temp<Box<Snapshot<Array<felt252>>>>([3]) -> ([3])
165+
return([3])
166+
167+
//! > ==========================================================================
168+
169+
//! > Test reboxing of a boxed, repeatedly snapshotted struct.
170+
171+
//! > test_runner_name
172+
test_function_generator(future_sierra:true)
159173

160-
//! > so we will see struct_boxed_deconstruct.
174+
//! > function_code
175+
fn foo(box: Box<@@@A>) -> Box<@@@Array<felt252>> {
176+
BoxTrait::new(box.unbox().a)
177+
}
178+
179+
//! > function_name
180+
foo
181+
182+
//! > module_code
183+
#[derive(Drop)]
184+
struct A {
185+
a: Array<felt252>,
186+
b: Array<felt252>,
187+
}
188+
189+
//! > semantic_diagnostics
190+
191+
//! > lowering_diagnostics
161192

162193
//! > sierra_code
163194
label_test::foo::0:
164-
unbox<Snapshot<test::A>>([0]) -> ([1])
165-
store_temp<Snapshot<test::A>>([1]) -> ([1])
166-
struct_snapshot_deconstruct<test::A>([1]) -> ([2], [3])
167-
drop<Snapshot<Array<felt252>>>([3]) -> ()
168-
into_box<Snapshot<Array<felt252>>>([2]) -> ([4])
169-
return([4])
195+
dup<Box<Snapshot<test::A>>>([0]) -> ([0], [1])
196+
unbox<Snapshot<test::A>>([1]) -> ([2])
197+
drop<Snapshot<test::A>>([2]) -> ()
198+
struct_boxed_deconstruct<Snapshot<test::A>>([0]) -> ([3], [4])
199+
drop<Box<Snapshot<Array<felt252>>>>([4]) -> ()
200+
store_temp<Box<Snapshot<Array<felt252>>>>([3]) -> ([3])
201+
return([3])

crates/cairo-lang-sierra-generator/src/utils.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,8 @@ pub fn struct_deconstruct_libfunc_id(
112112
let is_snapshot = long_id.generic_id == SnapshotType::id();
113113
let is_box = long_id.generic_id == BoxType::id();
114114
Ok(if is_snapshot {
115-
let concrete_enum_type =
116-
extract_matches!(&long_id.generic_args[0], GenericArg::Type).clone();
117-
get_libfunc_id_with_generic_arg(db, "struct_snapshot_deconstruct", concrete_enum_type)
115+
let concrete_type = extract_matches!(&long_id.generic_args[0], GenericArg::Type).clone();
116+
get_libfunc_id_with_generic_arg(db, "struct_snapshot_deconstruct", concrete_type)
118117
} else if is_box {
119118
let inner_ty = extract_matches!(&long_id.generic_args[0], GenericArg::Type).clone();
120119
get_libfunc_id_with_generic_arg(db, "struct_boxed_deconstruct", inner_ty)

0 commit comments

Comments
 (0)