@@ -448,3 +448,268 @@ test::fib@F0([0]: RangeCheck, [1]: GasBuiltin, [2]: felt252) -> (RangeCheck, Gas
448448test::fib[116-219]@F1([0]: RangeCheck, [1]: GasBuiltin, [2]: felt252, [3]: felt252, [4]: felt252, [5]: felt252) -> (RangeCheck, GasBuiltin, core::panics::PanicResult::<(core::felt252, core::felt252, core::felt252, ())>);
449449core::panic_with_const_felt252::<375233589013918064796019>@F2() -> (Tuple<core::panics::Panic, Array<felt252>>);
450450core::panic_with_felt252@F3([0]: felt252) -> (Tuple<core::panics::Panic, Array<felt252>>);
451+
452+ //! > ==========================================================================
453+
454+ //! > Loop that reads an ancestor as a snapshot (@a.b) while also mutating a nested field (a.b.c)
455+
456+ //! > must preserve the mutation. When `finalize_as_scope` promotes the snapped ancestor into
457+
458+ //! > usage/changes, the later usage-pruning pass subsumes its descendants so the loop reads and writes back the whole
459+
460+ //! > ancestor. For x=2 the result is 1*2*2=4 (0x4).
461+
462+ //! > test_runner_name
463+ SmallE2ETestRunner(test_data_function: loop_snap_mut, test_data_input: 2, test_data_output: 4)
464+
465+ //! > cairo_code
466+ #[derive(Drop)]
467+ struct Inner {
468+ c: felt252,
469+ }
470+ #[derive(Drop)]
471+ struct Outer {
472+ b: Inner,
473+ }
474+
475+ fn loop_snap_mut(x: felt252) -> felt252 {
476+ let mut a = Outer { b: Inner { c: 1 } };
477+ let mut i: felt252 = 0;
478+ loop {
479+ if i == x {
480+ break;
481+ }
482+ let _snap = @a.b;
483+ a.b.c = a.b.c * 2;
484+ i = i + 1;
485+ }
486+ a.b.c
487+ }
488+
489+ //! > casm
490+ [ap + 0] = [fp + -5], ap++;
491+ [ap + 0] = [fp + -4], ap++;
492+ [ap + 0] = 1, ap++;
493+ [ap + 0] = 0, ap++;
494+ [ap + 0] = [fp + -3], ap++;
495+ call rel 19;
496+ jmp rel 10 if [ap + -3] != 0;
497+ [ap + 0] = [ap + -5], ap++;
498+ [ap + 0] = [ap + -5], ap++;
499+ [ap + 0] = 0, ap++;
500+ [ap + 0] = 0, ap++;
501+ [ap + 0] = [ap + -6], ap++;
502+ ret;
503+ [ap + 0] = [ap + -5], ap++;
504+ [ap + 0] = [ap + -5], ap++;
505+ [ap + 0] = 1, ap++;
506+ [ap + 0] = [ap + -5], ap++;
507+ [ap + 0] = [ap + -5], ap++;
508+ ret;
509+ %{ memory[ap + 0] = 1270 <= memory[fp + -6] %}
510+ jmp rel 7 if [ap + 0] != 0, ap++;
511+ [ap + 0] = [fp + -6] + 340282366920938463463374607431768210186, ap++;
512+ [ap + -1] = [[fp + -7] + 0];
513+ jmp rel 28;
514+ [fp + -6] = [ap + 0] + 1270, ap++;
515+ [ap + -1] = [[fp + -7] + 0];
516+ [fp + -4] = [ap + 0] + [fp + -3], ap++;
517+ jmp rel 11 if [ap + -1] != 0;
518+ [ap + 0] = [fp + -7] + 1, ap++;
519+ [ap + 0] = [ap + -3] + 2070, ap++;
520+ [ap + 0] = 0, ap++;
521+ [ap + 0] = [fp + -5], ap++;
522+ [ap + 0] = [fp + -4], ap++;
523+ ret;
524+ [ap + 0] = [fp + -7] + 1, ap++;
525+ [ap + 0] = [ap + -3], ap++;
526+ [ap + 0] = [fp + -5] * 2, ap++;
527+ [ap + 0] = [fp + -4] + 1, ap++;
528+ [ap + 0] = [fp + -3], ap++;
529+ call rel -30;
530+ ret;
531+ call rel 10;
532+ [ap + 0] = [fp + -7] + 1, ap++;
533+ [ap + 0] = [fp + -6], ap++;
534+ [ap + 0] = 1, ap++;
535+ [ap + 0] = [ap + -5], ap++;
536+ [ap + 0] = [ap + -5], ap++;
537+ ret;
538+ [ap + 0] = 375233589013918064796019, ap++;
539+ call rel 3;
540+ ret;
541+ %{ memory[ap + 0] = segments.add() %}
542+ ap += 1;
543+ [fp + -3] = [[ap + -1] + 0];
544+ [ap + 0] = [ap + -1], ap++;
545+ [ap + 0] = [ap + -2] + 1, ap++;
546+ ret;
547+
548+ //! > function_costs
549+ test::loop_snap_mut: SmallOrderedMap({Const: 3170})
550+ test::loop_snap_mut[116-254]: SmallOrderedMap({Const: 1870})
551+ core::panic_with_const_felt252::<375233589013918064796019>: SmallOrderedMap({Const: 700})
552+ core::panic_with_felt252: SmallOrderedMap({Const: 400})
553+
554+ //! > sierra_code
555+ type felt252 = felt252 [storable: true, drop: true, dup: true, zero_sized: false];
556+ type core::panics::Panic = Struct<ut@core::panics::Panic> [storable: true, drop: true, dup: true, zero_sized: true];
557+ type Array<felt252> = Array<felt252> [storable: true, drop: true, dup: false, zero_sized: false];
558+ type Const<felt252, 375233589013918064796019> = Const<felt252, 375233589013918064796019> [storable: false, drop: false, dup: false, zero_sized: false];
559+ type Const<felt252, 2> = Const<felt252, 2> [storable: false, drop: false, dup: false, zero_sized: false];
560+ type NonZero<felt252> = NonZero<felt252> [storable: true, drop: true, dup: true, zero_sized: false];
561+ type Tuple<felt252> = Struct<ut@Tuple, felt252> [storable: true, drop: true, dup: true, zero_sized: false];
562+ type Tuple<core::panics::Panic, Array<felt252>> = Struct<ut@Tuple, core::panics::Panic, Array<felt252>> [storable: true, drop: true, dup: false, zero_sized: false];
563+ type core::panics::PanicResult::<(core::felt252,)> = Enum<ut@core::panics::PanicResult::<(core::felt252,)>, Tuple<felt252>, Tuple<core::panics::Panic, Array<felt252>>> [storable: true, drop: true, dup: false, zero_sized: false];
564+ type Unit = Struct<ut@Tuple> [storable: true, drop: true, dup: true, zero_sized: true];
565+ type test::Inner = Struct<ut@test::Inner, felt252> [storable: true, drop: true, dup: true, zero_sized: false];
566+ type Tuple<test::Inner, felt252, Unit> = Struct<ut@Tuple, test::Inner, felt252, Unit> [storable: true, drop: true, dup: true, zero_sized: false];
567+ type core::panics::PanicResult::<(test::Inner, core::felt252, ())> = Enum<ut@core::panics::PanicResult::<(test::Inner, core::felt252, ())>, Tuple<test::Inner, felt252, Unit>, Tuple<core::panics::Panic, Array<felt252>>> [storable: true, drop: true, dup: false, zero_sized: false];
568+ type GasBuiltin = GasBuiltin [storable: true, drop: false, dup: false, zero_sized: false];
569+ type RangeCheck = RangeCheck [storable: true, drop: false, dup: false, zero_sized: false];
570+ type Const<felt252, 0> = Const<felt252, 0> [storable: false, drop: false, dup: false, zero_sized: false];
571+ type Const<felt252, 1> = Const<felt252, 1> [storable: false, drop: false, dup: false, zero_sized: false];
572+
573+ libfunc disable_ap_tracking = disable_ap_tracking;
574+ libfunc const_as_immediate<Const<felt252, 1>> = const_as_immediate<Const<felt252, 1>>;
575+ libfunc const_as_immediate<Const<felt252, 0>> = const_as_immediate<Const<felt252, 0>>;
576+ libfunc snapshot_take<felt252> = snapshot_take<felt252>;
577+ libfunc drop<felt252> = drop<felt252>;
578+ libfunc struct_construct<test::Inner> = struct_construct<test::Inner>;
579+ libfunc store_temp<RangeCheck> = store_temp<RangeCheck>;
580+ libfunc store_temp<GasBuiltin> = store_temp<GasBuiltin>;
581+ libfunc store_temp<test::Inner> = store_temp<test::Inner>;
582+ libfunc store_temp<felt252> = store_temp<felt252>;
583+ libfunc function_call<user@test::loop_snap_mut[116-254]> = function_call<user@test::loop_snap_mut[116-254]>;
584+ libfunc enum_match<core::panics::PanicResult::<(test::Inner, core::felt252, ())>> = enum_match<core::panics::PanicResult::<(test::Inner, core::felt252, ())>>;
585+ libfunc branch_align = branch_align;
586+ libfunc redeposit_gas = redeposit_gas;
587+ libfunc struct_deconstruct<Tuple<test::Inner, felt252, Unit>> = struct_deconstruct<Tuple<test::Inner, felt252, Unit>>;
588+ libfunc drop<Unit> = drop<Unit>;
589+ libfunc struct_deconstruct<test::Inner> = struct_deconstruct<test::Inner>;
590+ libfunc struct_construct<Tuple<felt252>> = struct_construct<Tuple<felt252>>;
591+ libfunc enum_init<core::panics::PanicResult::<(core::felt252,)>, 0> = enum_init<core::panics::PanicResult::<(core::felt252,)>, 0>;
592+ libfunc store_temp<core::panics::PanicResult::<(core::felt252,)>> = store_temp<core::panics::PanicResult::<(core::felt252,)>>;
593+ libfunc enum_init<core::panics::PanicResult::<(core::felt252,)>, 1> = enum_init<core::panics::PanicResult::<(core::felt252,)>, 1>;
594+ libfunc withdraw_gas = withdraw_gas;
595+ libfunc dup<felt252> = dup<felt252>;
596+ libfunc rename<felt252> = rename<felt252>;
597+ libfunc felt252_sub = felt252_sub;
598+ libfunc felt252_is_zero = felt252_is_zero;
599+ libfunc struct_construct<Unit> = struct_construct<Unit>;
600+ libfunc struct_construct<Tuple<test::Inner, felt252, Unit>> = struct_construct<Tuple<test::Inner, felt252, Unit>>;
601+ libfunc enum_init<core::panics::PanicResult::<(test::Inner, core::felt252, ())>, 0> = enum_init<core::panics::PanicResult::<(test::Inner, core::felt252, ())>, 0>;
602+ libfunc store_temp<core::panics::PanicResult::<(test::Inner, core::felt252, ())>> = store_temp<core::panics::PanicResult::<(test::Inner, core::felt252, ())>>;
603+ libfunc drop<NonZero<felt252>> = drop<NonZero<felt252>>;
604+ libfunc const_as_immediate<Const<felt252, 2>> = const_as_immediate<Const<felt252, 2>>;
605+ libfunc felt252_mul = felt252_mul;
606+ libfunc felt252_add = felt252_add;
607+ libfunc drop<test::Inner> = drop<test::Inner>;
608+ libfunc function_call<user@core::panic_with_const_felt252::<375233589013918064796019>> = function_call<user@core::panic_with_const_felt252::<375233589013918064796019>>;
609+ libfunc enum_init<core::panics::PanicResult::<(test::Inner, core::felt252, ())>, 1> = enum_init<core::panics::PanicResult::<(test::Inner, core::felt252, ())>, 1>;
610+ libfunc const_as_immediate<Const<felt252, 375233589013918064796019>> = const_as_immediate<Const<felt252, 375233589013918064796019>>;
611+ libfunc function_call<user@core::panic_with_felt252> = function_call<user@core::panic_with_felt252>;
612+ libfunc array_new<felt252> = array_new<felt252>;
613+ libfunc array_append<felt252> = array_append<felt252>;
614+ libfunc struct_construct<core::panics::Panic> = struct_construct<core::panics::Panic>;
615+ libfunc struct_construct<Tuple<core::panics::Panic, Array<felt252>>> = struct_construct<Tuple<core::panics::Panic, Array<felt252>>>;
616+ libfunc store_temp<Tuple<core::panics::Panic, Array<felt252>>> = store_temp<Tuple<core::panics::Panic, Array<felt252>>>;
617+
618+ F0:
619+ disable_ap_tracking() -> ();
620+ const_as_immediate<Const<felt252, 1>>() -> ([3]);
621+ const_as_immediate<Const<felt252, 0>>() -> ([4]);
622+ snapshot_take<felt252>([2]) -> ([5], [6]);
623+ drop<felt252>([5]) -> ();
624+ struct_construct<test::Inner>([3]) -> ([7]);
625+ store_temp<RangeCheck>([0]) -> ([0]);
626+ store_temp<GasBuiltin>([1]) -> ([1]);
627+ store_temp<test::Inner>([7]) -> ([7]);
628+ store_temp<felt252>([4]) -> ([4]);
629+ store_temp<felt252>([6]) -> ([6]);
630+ function_call<user@test::loop_snap_mut[116-254]>([0], [1], [7], [4], [6]) -> ([8], [9], [10]);
631+ enum_match<core::panics::PanicResult::<(test::Inner, core::felt252, ())>>([10]) { fallthrough([11]) F0_B0([12]) };
632+ branch_align() -> ();
633+ redeposit_gas([9]) -> ([13]);
634+ struct_deconstruct<Tuple<test::Inner, felt252, Unit>>([11]) -> ([14], [15], [16]);
635+ drop<felt252>([15]) -> ();
636+ drop<Unit>([16]) -> ();
637+ struct_deconstruct<test::Inner>([14]) -> ([17]);
638+ struct_construct<Tuple<felt252>>([17]) -> ([18]);
639+ enum_init<core::panics::PanicResult::<(core::felt252,)>, 0>([18]) -> ([19]);
640+ store_temp<RangeCheck>([8]) -> ([8]);
641+ store_temp<GasBuiltin>([13]) -> ([13]);
642+ store_temp<core::panics::PanicResult::<(core::felt252,)>>([19]) -> ([19]);
643+ return([8], [13], [19]);
644+ F0_B0:
645+ branch_align() -> ();
646+ enum_init<core::panics::PanicResult::<(core::felt252,)>, 1>([12]) -> ([20]);
647+ store_temp<RangeCheck>([8]) -> ([8]);
648+ store_temp<GasBuiltin>([9]) -> ([9]);
649+ store_temp<core::panics::PanicResult::<(core::felt252,)>>([20]) -> ([20]);
650+ return([8], [9], [20]);
651+ F1:
652+ disable_ap_tracking() -> ();
653+ withdraw_gas([0], [1]) { fallthrough([5], [6]) F1_B1([7], [8]) };
654+ branch_align() -> ();
655+ dup<felt252>([4]) -> ([4], [9]);
656+ rename<felt252>([9]) -> ([10]);
657+ dup<felt252>([3]) -> ([3], [11]);
658+ felt252_sub([11], [10]) -> ([12]);
659+ store_temp<felt252>([12]) -> ([12]);
660+ felt252_is_zero([12]) { fallthrough() F1_B0([13]) };
661+ branch_align() -> ();
662+ drop<felt252>([4]) -> ();
663+ redeposit_gas([6]) -> ([14]);
664+ struct_construct<Unit>() -> ([15]);
665+ struct_construct<Tuple<test::Inner, felt252, Unit>>([2], [3], [15]) -> ([16]);
666+ enum_init<core::panics::PanicResult::<(test::Inner, core::felt252, ())>, 0>([16]) -> ([17]);
667+ store_temp<RangeCheck>([5]) -> ([5]);
668+ store_temp<GasBuiltin>([14]) -> ([14]);
669+ store_temp<core::panics::PanicResult::<(test::Inner, core::felt252, ())>>([17]) -> ([17]);
670+ return([5], [14], [17]);
671+ F1_B0:
672+ branch_align() -> ();
673+ drop<NonZero<felt252>>([13]) -> ();
674+ redeposit_gas([6]) -> ([18]);
675+ struct_deconstruct<test::Inner>([2]) -> ([19]);
676+ const_as_immediate<Const<felt252, 2>>() -> ([20]);
677+ felt252_mul([19], [20]) -> ([21]);
678+ const_as_immediate<Const<felt252, 1>>() -> ([22]);
679+ felt252_add([3], [22]) -> ([23]);
680+ struct_construct<test::Inner>([21]) -> ([24]);
681+ store_temp<RangeCheck>([5]) -> ([5]);
682+ store_temp<GasBuiltin>([18]) -> ([18]);
683+ store_temp<test::Inner>([24]) -> ([24]);
684+ store_temp<felt252>([23]) -> ([23]);
685+ store_temp<felt252>([4]) -> ([4]);
686+ function_call<user@test::loop_snap_mut[116-254]>([5], [18], [24], [23], [4]) -> ([25], [26], [27]);
687+ return([25], [26], [27]);
688+ F1_B1:
689+ branch_align() -> ();
690+ drop<felt252>([4]) -> ();
691+ drop<felt252>([3]) -> ();
692+ drop<test::Inner>([2]) -> ();
693+ function_call<user@core::panic_with_const_felt252::<375233589013918064796019>>() -> ([28]);
694+ enum_init<core::panics::PanicResult::<(test::Inner, core::felt252, ())>, 1>([28]) -> ([29]);
695+ store_temp<RangeCheck>([7]) -> ([7]);
696+ store_temp<GasBuiltin>([8]) -> ([8]);
697+ store_temp<core::panics::PanicResult::<(test::Inner, core::felt252, ())>>([29]) -> ([29]);
698+ return([7], [8], [29]);
699+ F2:
700+ const_as_immediate<Const<felt252, 375233589013918064796019>>() -> ([0]);
701+ store_temp<felt252>([0]) -> ([0]);
702+ function_call<user@core::panic_with_felt252>([0]) -> ([1]);
703+ return([1]);
704+ F3:
705+ array_new<felt252>() -> ([1]);
706+ array_append<felt252>([1], [0]) -> ([2]);
707+ struct_construct<core::panics::Panic>() -> ([3]);
708+ struct_construct<Tuple<core::panics::Panic, Array<felt252>>>([3], [2]) -> ([4]);
709+ store_temp<Tuple<core::panics::Panic, Array<felt252>>>([4]) -> ([4]);
710+ return([4]);
711+
712+ test::loop_snap_mut@F0([0]: RangeCheck, [1]: GasBuiltin, [2]: felt252) -> (RangeCheck, GasBuiltin, core::panics::PanicResult::<(core::felt252,)>);
713+ test::loop_snap_mut[116-254]@F1([0]: RangeCheck, [1]: GasBuiltin, [2]: test::Inner, [3]: felt252, [4]: felt252) -> (RangeCheck, GasBuiltin, core::panics::PanicResult::<(test::Inner, core::felt252, ())>);
714+ core::panic_with_const_felt252::<375233589013918064796019>@F2() -> (Tuple<core::panics::Panic, Array<felt252>>);
715+ core::panic_with_felt252@F3([0]: felt252) -> (Tuple<core::panics::Panic, Array<felt252>>);
0 commit comments