@@ -608,16 +608,11 @@ impl Instruction {
608608 }
609609 }
610610 Instruction :: ArrayGet { array, index } => {
611- let array = dfg. get_array_constant ( * array) ;
612- let index = dfg. get_numeric_constant ( * index) ;
613- if let ( Some ( ( array, _) ) , Some ( index) ) = ( array, index) {
614- let index =
615- index. try_to_u32 ( ) . expect ( "Expected array index to fit in u32" ) as usize ;
616- if index < array. len ( ) {
617- return SimplifiedTo ( array[ index] ) ;
618- }
611+ if let Some ( index) = dfg. get_numeric_constant ( * index) {
612+ try_optimize_array_get_from_previous_set ( dfg, * array, index)
613+ } else {
614+ None
619615 }
620- None
621616 }
622617 Instruction :: ArraySet { array, index, value, .. } => {
623618 let array = dfg. get_array_constant ( * array) ;
@@ -744,6 +739,65 @@ impl Instruction {
744739 }
745740}
746741
742+ /// Given a chain of operations like:
743+ /// v1 = array_set [10, 11, 12], index 1, value: 5
744+ /// v2 = array_set v1, index 2, value: 6
745+ /// v3 = array_set v2, index 2, value: 7
746+ /// v4 = array_get v3, index 1
747+ ///
748+ /// We want to optimize `v4` to `10`. To do this we need to follow the array value
749+ /// through several array sets. For each array set:
750+ /// - If the index is non-constant we fail the optimization since any index may be changed
751+ /// - If the index is constant and is our target index, we conservatively fail the optimization
752+ /// in case the array_set is disabled from a previous `enable_side_effects_if` and the array get
753+ /// was not.
754+ /// - Otherwise, we check the array value of the array set.
755+ /// - If the array value is constant, we use that array.
756+ /// - If the array value is from a previous array-set, we recur.
757+ fn try_optimize_array_get_from_previous_set (
758+ dfg : & DataFlowGraph ,
759+ mut array_id : Id < Value > ,
760+ target_index : FieldElement ,
761+ ) -> SimplifyResult {
762+ let mut elements = None ;
763+
764+ // Arbitrary number of maximum tries just to prevent this optimization from taking too long.
765+ let max_tries = 5 ;
766+ for _ in 0 ..max_tries {
767+ match & dfg[ array_id] {
768+ Value :: Instruction { instruction, .. } => {
769+ match & dfg[ * instruction] {
770+ Instruction :: ArraySet { array, index, value, .. } => {
771+ if let Some ( constant) = dfg. get_numeric_constant ( * index) {
772+ if constant == target_index {
773+ return SimplifyResult :: SimplifiedTo ( * value) ;
774+ }
775+
776+ array_id = * array; // recur
777+ } else {
778+ return SimplifyResult :: None ;
779+ }
780+ }
781+ _ => return SimplifyResult :: None ,
782+ }
783+ }
784+ Value :: Array { array, typ : _ } => {
785+ elements = Some ( array. clone ( ) ) ;
786+ break ;
787+ }
788+ _ => return SimplifyResult :: None ,
789+ }
790+ }
791+
792+ if let ( Some ( array) , Some ( index) ) = ( elements, target_index. try_to_u64 ( ) ) {
793+ let index = index as usize ;
794+ if index < array. len ( ) {
795+ return SimplifyResult :: SimplifiedTo ( array[ index] ) ;
796+ }
797+ }
798+ SimplifyResult :: None
799+ }
800+
747801pub ( crate ) type ErrorType = HirType ;
748802
749803pub ( crate ) fn error_selector_from_type ( typ : & ErrorType ) -> ErrorSelector {
0 commit comments