Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: handle constant index operations on simple slices #3464

Merged
merged 3 commits into from
Nov 9, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 62 additions & 61 deletions compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,75 +658,76 @@
store_value: Option<ValueId>,
) -> Result<bool, RuntimeError> {
let index_const = dfg.get_numeric_constant(index);
match dfg.type_of_value(array) {
Type::Array(_, _) => {
match self.convert_value(array, dfg) {
AcirValue::Var(acir_var, _) => {
return Err(RuntimeError::InternalError(InternalError::UnExpected {
expected: "an array value".to_string(),
found: format!("{acir_var:?}"),
call_stack: self.acir_context.get_call_stack(),
}))
}
AcirValue::Array(array) => {
if let Some(index_const) = index_const {
let array_size = array.len();
let index = match index_const.try_to_u64() {
Some(index_const) => index_const as usize,
None => {
let call_stack = self.acir_context.get_call_stack();
return Err(RuntimeError::TypeConversion {
from: "array index".to_string(),
into: "u64".to_string(),
call_stack,
});
let value_type = dfg.type_of_value(array);
let (Type::Array(element_types, _) | Type::Slice(element_types)) = &value_type else {
unreachable!("ICE: expected array or slice type");

};

// TODO(#3188): Need to be able to handle constant index for slices to seriously reduce
// constraint sizes of nested slices
// This can only be done if we accurately flatten nested slices as otherwise we will reach
// index out of bounds errors. If the slice is already flat then we can treat them similarly to arrays.
if matches!(value_type, Type::Slice(_))
&& element_types.iter().any(|element| element.contains_slice_element())
{
return Ok(false);
}

match self.convert_value(array, dfg) {
AcirValue::Var(acir_var, _) => {
return Err(RuntimeError::InternalError(InternalError::UnExpected {
expected: "an array value".to_string(),
found: format!("{acir_var:?}"),
call_stack: self.acir_context.get_call_stack(),
}))
}
AcirValue::Array(array) => {
if let Some(index_const) = index_const {
let array_size = array.len();
let index = match index_const.try_to_u64() {
Some(index_const) => index_const as usize,
None => {
let call_stack = self.acir_context.get_call_stack();
return Err(RuntimeError::TypeConversion {
from: "array index".to_string(),
into: "u64".to_string(),
call_stack,
});
}
};
if self.acir_context.is_constant_one(&self.current_side_effects_enabled_var) {
// Report the error if side effects are enabled.
if index >= array_size {
let call_stack = self.acir_context.get_call_stack();
return Err(RuntimeError::IndexOutOfBounds {
index,
array_size,
call_stack,
});
} else {
let value = match store_value {
Some(store_value) => {
let store_value = self.convert_value(store_value, dfg);
AcirValue::Array(array.update(index, store_value))
}
None => array[index].clone(),
};
if self
.acir_context
.is_constant_one(&self.current_side_effects_enabled_var)
{
// Report the error if side effects are enabled.
if index >= array_size {
let call_stack = self.acir_context.get_call_stack();
return Err(RuntimeError::IndexOutOfBounds {
index,
array_size,
call_stack,
});
} else {
let value = match store_value {
Some(store_value) => {
let store_value = self.convert_value(store_value, dfg);
AcirValue::Array(array.update(index, store_value))
}
None => array[index].clone(),
};

self.define_result(dfg, instruction, value);
return Ok(true);
}
}
// If there is a predicate and the index is not out of range, we can directly perform the read
else if index < array_size && store_value.is_none() {
self.define_result(dfg, instruction, array[index].clone());
return Ok(true);
}
self.define_result(dfg, instruction, value);
return Ok(true);
}
}
AcirValue::DynamicArray(_) => (),
// If there is a predicate and the index is not out of range, we can directly perform the read
else if index < array_size && store_value.is_none() {
self.define_result(dfg, instruction, array[index].clone());
return Ok(true);
}
}
}
Type::Slice(_) => {
// TODO(#3188): Need to be able to handle constant index for slices to seriously reduce
// constraint sizes of nested slices
// This can only be done if we accurately flatten nested slices as other we will reach
// index out of bounds errors.
AcirValue::DynamicArray(_) => (),
};

// Do nothing we only want dynamic checks for slices
}
_ => unreachable!("ICE: expected array or slice type"),
}
Ok(false)
}

Expand Down Expand Up @@ -891,7 +892,7 @@

// The first max size is going to be the length of the parent slice
// As we are fetching from the parent slice we just want its internal
// slize sizes.

Check warning on line 895 in compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (slize)
let slice_sizes = slice_sizes[1..].to_vec();

let value = self.array_get_value(&res_typ, block_id, &mut var_index, &slice_sizes)?;
Expand Down Expand Up @@ -920,7 +921,7 @@
// Read the value from the array at the specified index
let read = self.acir_context.read_from_memory(block_id, var_index)?;

// Incremement the var_index in case of a nested array

Check warning on line 924 in compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (Incremement)
*var_index = self.acir_context.add_var(*var_index, one)?;

let typ = AcirType::NumericType(numeric_type);
Expand Down Expand Up @@ -1057,7 +1058,7 @@
AcirValue::Var(store_var, _) => {
// Write the new value into the new array at the specified index
self.acir_context.write_to_memory(block_id, var_index, &store_var)?;
// Incremement the var_index in case of a nested array

Check warning on line 1061 in compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (Incremement)
*var_index = self.acir_context.add_var(*var_index, one)?;
}
AcirValue::Array(values) => {
Expand Down
Loading