Skip to content

Commit 09d818a

Browse files
authored
Merge e3f7fcf into 5192e53
2 parents 5192e53 + e3f7fcf commit 09d818a

1 file changed

Lines changed: 63 additions & 9 deletions

File tree

compiler/noirc_evaluator/src/ssa/ir/instruction.rs

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
747801
pub(crate) type ErrorType = HirType;
748802

749803
pub(crate) fn error_selector_from_type(typ: &ErrorType) -> ErrorSelector {

0 commit comments

Comments
 (0)