Skip to content

Commit 5ebbc54

Browse files
committed
feat: handle constant index operations on simple slices
1 parent 52daaec commit 5ebbc54

File tree

1 file changed

+60
-61
lines changed
  • compiler/noirc_evaluator/src/ssa/acir_gen

1 file changed

+60
-61
lines changed

compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs

Lines changed: 60 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -658,75 +658,74 @@ impl Context {
658658
store_value: Option<ValueId>,
659659
) -> Result<bool, RuntimeError> {
660660
let index_const = dfg.get_numeric_constant(index);
661-
match dfg.type_of_value(array) {
662-
Type::Array(_, _) => {
663-
match self.convert_value(array, dfg) {
664-
AcirValue::Var(acir_var, _) => {
665-
return Err(RuntimeError::InternalError(InternalError::UnExpected {
666-
expected: "an array value".to_string(),
667-
found: format!("{acir_var:?}"),
668-
call_stack: self.acir_context.get_call_stack(),
669-
}))
670-
}
671-
AcirValue::Array(array) => {
672-
if let Some(index_const) = index_const {
673-
let array_size = array.len();
674-
let index = match index_const.try_to_u64() {
675-
Some(index_const) => index_const as usize,
676-
None => {
677-
let call_stack = self.acir_context.get_call_stack();
678-
return Err(RuntimeError::TypeConversion {
679-
from: "array index".to_string(),
680-
into: "u64".to_string(),
681-
call_stack,
682-
});
661+
let value_type = dfg.type_of_value(array);
662+
let (Type::Array(element_types, _) | Type::Slice(element_types)) = value_type else {
663+
unreachable!("ICE: expected array or slice type");
664+
665+
};
666+
667+
// TODO(#3188): Need to be able to handle constant index for slices to seriously reduce
668+
// constraint sizes of nested slices
669+
// This can only be done if we accurately flatten nested slices as other we will reach
670+
// index out of bounds errors.
671+
if element_types.iter().any(|element| element.contains_slice_element()) {
672+
return Ok(false);
673+
}
674+
675+
match self.convert_value(array, dfg) {
676+
AcirValue::Var(acir_var, _) => {
677+
return Err(RuntimeError::InternalError(InternalError::UnExpected {
678+
expected: "an array value".to_string(),
679+
found: format!("{acir_var:?}"),
680+
call_stack: self.acir_context.get_call_stack(),
681+
}))
682+
}
683+
AcirValue::Array(array) => {
684+
if let Some(index_const) = index_const {
685+
let array_size = array.len();
686+
let index = match index_const.try_to_u64() {
687+
Some(index_const) => index_const as usize,
688+
None => {
689+
let call_stack = self.acir_context.get_call_stack();
690+
return Err(RuntimeError::TypeConversion {
691+
from: "array index".to_string(),
692+
into: "u64".to_string(),
693+
call_stack,
694+
});
695+
}
696+
};
697+
if self.acir_context.is_constant_one(&self.current_side_effects_enabled_var) {
698+
// Report the error if side effects are enabled.
699+
if index >= array_size {
700+
let call_stack = self.acir_context.get_call_stack();
701+
return Err(RuntimeError::IndexOutOfBounds {
702+
index,
703+
array_size,
704+
call_stack,
705+
});
706+
} else {
707+
let value = match store_value {
708+
Some(store_value) => {
709+
let store_value = self.convert_value(store_value, dfg);
710+
AcirValue::Array(array.update(index, store_value))
683711
}
712+
None => array[index].clone(),
684713
};
685-
if self
686-
.acir_context
687-
.is_constant_one(&self.current_side_effects_enabled_var)
688-
{
689-
// Report the error if side effects are enabled.
690-
if index >= array_size {
691-
let call_stack = self.acir_context.get_call_stack();
692-
return Err(RuntimeError::IndexOutOfBounds {
693-
index,
694-
array_size,
695-
call_stack,
696-
});
697-
} else {
698-
let value = match store_value {
699-
Some(store_value) => {
700-
let store_value = self.convert_value(store_value, dfg);
701-
AcirValue::Array(array.update(index, store_value))
702-
}
703-
None => array[index].clone(),
704-
};
705714

706-
self.define_result(dfg, instruction, value);
707-
return Ok(true);
708-
}
709-
}
710-
// If there is a predicate and the index is not out of range, we can directly perform the read
711-
else if index < array_size && store_value.is_none() {
712-
self.define_result(dfg, instruction, array[index].clone());
713-
return Ok(true);
714-
}
715+
self.define_result(dfg, instruction, value);
716+
return Ok(true);
715717
}
716718
}
717-
AcirValue::DynamicArray(_) => (),
719+
// If there is a predicate and the index is not out of range, we can directly perform the read
720+
else if index < array_size && store_value.is_none() {
721+
self.define_result(dfg, instruction, array[index].clone());
722+
return Ok(true);
723+
}
718724
}
719725
}
720-
Type::Slice(_) => {
721-
// TODO(#3188): Need to be able to handle constant index for slices to seriously reduce
722-
// constraint sizes of nested slices
723-
// This can only be done if we accurately flatten nested slices as other we will reach
724-
// index out of bounds errors.
726+
AcirValue::DynamicArray(_) => (),
727+
};
725728

726-
// Do nothing we only want dynamic checks for slices
727-
}
728-
_ => unreachable!("ICE: expected array or slice type"),
729-
}
730729
Ok(false)
731730
}
732731

0 commit comments

Comments
 (0)