Skip to content
Closed
Show file tree
Hide file tree
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
92 changes: 23 additions & 69 deletions compiler/noirc_evaluator/src/acir/arrays.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,19 +235,14 @@ impl Context<'_> {
}

let array_typ = dfg.type_of_value(array);
let offset = self.compute_offset(instruction, dfg, &array_typ);
let (new_index, new_value) = self.convert_array_operation_inputs(
array,
dfg,
index,
store_value,
offset.unwrap_or_default(),
)?;
let offset = self.compute_offset(instruction, dfg, &array_typ, store_value);
let (new_index, new_value) =
self.convert_array_operation_inputs(array, dfg, index, store_value, offset)?;

if let Some(new_value) = new_value {
self.array_set(instruction, new_index, new_value, dfg, mutable)?;
} else {
self.array_get(instruction, array, new_index, dfg, offset.is_none())?;
self.array_get(instruction, array, new_index, dfg)?;
}

Ok(())
Expand Down Expand Up @@ -388,21 +383,27 @@ impl Context<'_> {
instruction: InstructionId,
dfg: &DataFlowGraph,
array_typ: &Type,
) -> Option<usize> {
let is_simple_array = dfg.instruction_results(instruction).len() == 1
&& (array_has_constant_element_size(array_typ) == Some(1));
if is_simple_array {
let result_type = dfg.type_of_value(dfg.instruction_results(instruction)[0]);
match array_typ {
Type::Array(item_type, _) | Type::Vector(item_type) => item_type
.iter()
.enumerate()
.find_map(|(index, typ)| (result_type == *typ).then_some(index)),
_ => None,
}
store_value: Option<ValueId>,
) -> usize {
let value_at_index = if let Some(store_value) = store_value {
store_value
} else {
None
let [result] = dfg.instruction_result(instruction);
result
};
let value_type = dfg.type_of_value(value_at_index);
match array_typ {
Type::Array(item_type, _) | Type::Vector(item_type) => {
for (index, typ) in item_type.iter().enumerate() {
if &value_type == typ {
return index;
}
}
}
_ => (),
}

unreachable!("ICE: should always be able to compute offset for array operation");
}

/// We need to properly setup the inputs for array operations in ACIR.
Expand Down Expand Up @@ -584,13 +585,11 @@ impl Context<'_> {
array: ValueId,
var_index: AcirVar,
dfg: &DataFlowGraph,
index_side_effect: bool,
) -> Result<(), RuntimeError> {
let block_id = self.ensure_array_is_initialized(array, dfg)?;
let [result] = dfg.instruction_result(instruction);
let res_typ = dfg.type_of_value(result);
let value = self.load_array_value(array, block_id, var_index, &res_typ, dfg)?;
let value = self.apply_index_side_effects(array, value, index_side_effect, dfg)?;
self.define_result(dfg, instruction, value);
Ok(())
}
Expand Down Expand Up @@ -645,51 +644,6 @@ impl Context<'_> {
}
}

/// Applies predication logic on the result in case the read under a false predicate
/// returns a value with a larger type that may later trigger an overflow.
/// Ensures values read under false predicate are zeroed out if types don’t align.
/// This is done recursively for nested arrays.
fn apply_index_side_effects(
&mut self,
array: ValueId,
mut value: AcirValue,
mut index_side_effect: bool,
dfg: &DataFlowGraph,
) -> Result<AcirValue, RuntimeError> {
match &value {
AcirValue::Var(acir_var, typ) => {
// If we read under a false predicate, we will read element 0, which has `numeric_type`.
// The variable we expect to read is of `typ`. We check whether reading 0 is compatible with `typ`.
let array_typ = dfg.type_of_value(array);
if let Type::Numeric(numeric_type) = array_typ.first()
&& numeric_type.bit_size::<FieldElement>() <= typ.bit_size::<FieldElement>()
{
// first element is compatible
index_side_effect = false;
}

if index_side_effect {
value = AcirValue::Var(
self.acir_context
.mul_var(*acir_var, self.current_side_effects_enabled_var)?,
*typ,
);
}
}
AcirValue::Array(vector) => {
let new_values = try_vecmap(vector.iter(), |val| {
self.apply_index_side_effects(array, val.clone(), index_side_effect, dfg)
})?;
value = AcirValue::Array(im::Vector::from(new_values));
}
AcirValue::DynamicArray(_) => {
unreachable!("ICE: Nested dynamic arrays are not supported")
}
}

Ok(value)
}

pub(super) fn array_get_value(
&mut self,
ssa_type: &Type,
Expand Down
8 changes: 0 additions & 8 deletions compiler/noirc_evaluator/src/ssa/ir/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,14 +314,6 @@ impl Type {
}
}

pub(crate) fn first(&self) -> Type {
match self {
Type::Numeric(_) | Type::Function => self.clone(),
Type::Reference(typ) => typ.first(),
Type::Vector(element_types) | Type::Array(element_types, _) => element_types[0].first(),
}
}

/// True if this is a reference type or if it is a composite type which contains a reference.
pub(crate) fn contains_reference(&self) -> bool {
match self {
Expand Down
Loading