Skip to content

Commit

Permalink
feat: Reduce memory consumption by storing array length as u32 duri…
Browse files Browse the repository at this point in the history
…ng SSA (#6606)

Co-authored-by: jfecher <[email protected]>
  • Loading branch information
TomAFrench and jfecher authored Dec 2, 2024
1 parent 68c7043 commit 6196d05
Show file tree
Hide file tree
Showing 19 changed files with 74 additions and 88 deletions.
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/acir/acir_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl<'a> From<&'a SsaType> for AcirType {
SsaType::Numeric(numeric_type) => AcirType::NumericType(*numeric_type),
SsaType::Array(elements, size) => {
let elements = elements.iter().map(|e| e.into()).collect();
AcirType::Array(elements, *size)
AcirType::Array(elements, *size as usize)
}
_ => unreachable!("The type {value} cannot be represented in ACIR"),
}
Expand Down
27 changes: 12 additions & 15 deletions compiler/noirc_evaluator/src/acir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ impl<'a> Context<'a> {
AcirValue::Array(_) => {
let block_id = self.block_id(param_id);
let len = if matches!(typ, Type::Array(_, _)) {
typ.flattened_size()
typ.flattened_size() as usize
} else {
return Err(InternalError::Unexpected {
expected: "Block params should be an array".to_owned(),
Expand Down Expand Up @@ -816,7 +816,9 @@ impl<'a> Context<'a> {
let inputs = vecmap(arguments, |arg| self.convert_value(*arg, dfg));
let output_count = result_ids
.iter()
.map(|result_id| dfg.type_of_value(*result_id).flattened_size())
.map(|result_id| {
dfg.type_of_value(*result_id).flattened_size() as usize
})
.sum();

let Some(acir_function_id) =
Expand Down Expand Up @@ -948,7 +950,7 @@ impl<'a> Context<'a> {
let block_id = self.block_id(&array_id);
let array_typ = dfg.type_of_value(array_id);
let len = if matches!(array_typ, Type::Array(_, _)) {
array_typ.flattened_size()
array_typ.flattened_size() as usize
} else {
Self::flattened_value_size(&output)
};
Expand Down Expand Up @@ -1444,7 +1446,7 @@ impl<'a> Context<'a> {
// a separate SSA value and restrictions on slice indices should be generated elsewhere in the SSA.
let array_typ = dfg.type_of_value(array);
let array_len = if !array_typ.contains_slice_element() {
array_typ.flattened_size()
array_typ.flattened_size() as usize
} else {
self.flattened_slice_size(array, dfg)
};
Expand Down Expand Up @@ -1539,7 +1541,7 @@ impl<'a> Context<'a> {
let value = self.convert_value(array, dfg);
let array_typ = dfg.type_of_value(array);
let len = if !array_typ.contains_slice_element() {
array_typ.flattened_size()
array_typ.flattened_size() as usize
} else {
self.flattened_slice_size(array, dfg)
};
Expand Down Expand Up @@ -1810,7 +1812,7 @@ impl<'a> Context<'a> {

return_values
.iter()
.fold(0, |acc, value_id| acc + dfg.type_of_value(*value_id).flattened_size())
.fold(0, |acc, value_id| acc + dfg.type_of_value(*value_id).flattened_size() as usize)
}

/// Converts an SSA terminator's return values into their ACIR representations
Expand Down Expand Up @@ -2156,7 +2158,7 @@ impl<'a> Context<'a> {
let inputs = vecmap(&arguments_no_slice_len, |arg| self.convert_value(*arg, dfg));

let output_count = result_ids.iter().fold(0usize, |sum, result_id| {
sum + dfg.try_get_array_length(*result_id).unwrap_or(1)
sum + dfg.try_get_array_length(*result_id).unwrap_or(1) as usize
});

let vars = self.acir_context.black_box_function(black_box, inputs, output_count)?;
Expand All @@ -2180,7 +2182,7 @@ impl<'a> Context<'a> {
endian,
field,
radix,
array_length as u32,
array_length,
result_type[0].clone().into(),
)
.map(|array| vec![array])
Expand All @@ -2194,12 +2196,7 @@ impl<'a> Context<'a> {
};

self.acir_context
.bit_decompose(
endian,
field,
array_length as u32,
result_type[0].clone().into(),
)
.bit_decompose(endian, field, array_length, result_type[0].clone().into())
.map(|array| vec![array])
}
Intrinsic::ArrayLen => {
Expand All @@ -2220,7 +2217,7 @@ impl<'a> Context<'a> {
let acir_value = self.convert_value(slice_contents, dfg);

let array_len = if !slice_typ.contains_slice_element() {
slice_typ.flattened_size()
slice_typ.flattened_size() as usize
} else {
self.flattened_slice_size(slice_contents, dfg)
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1823,7 +1823,7 @@ impl<'block> BrilligBlock<'block> {
Type::Array(_, nested_size) => {
let inner_array = BrilligArray {
pointer: self.brillig_context.allocate_register(),
size: *nested_size,
size: *nested_size as usize,
};
self.allocate_foreign_call_result_array(element_type, inner_array);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ pub(crate) fn allocate_value<F, Registers: RegisterAllocator>(
}
Type::Array(item_typ, elem_count) => BrilligVariable::BrilligArray(BrilligArray {
pointer: brillig_context.allocate_register(),
size: compute_array_length(&item_typ, elem_count),
size: compute_array_length(&item_typ, elem_count as usize),
}),
Type::Slice(_) => BrilligVariable::BrilligVector(BrilligVector {
pointer: brillig_context.allocate_register(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl FunctionContext {
vecmap(item_type.iter(), |item_typ| {
FunctionContext::ssa_type_to_parameter(item_typ)
}),
*size,
*size as usize,
),
Type::Slice(_) => {
panic!("ICE: Slice parameters cannot be derived from type information")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType {
),
Type::Array(elem_type, size) => HeapValueType::Array {
value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(),
size: typ.element_size() * size,
size: typ.element_size() * *size as usize,
},
Type::Slice(elem_type) => HeapValueType::Vector {
value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(),
Expand Down
8 changes: 5 additions & 3 deletions compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ impl FunctionBuilder {
for value in values {
self.add_to_data_bus(*value, &mut databus);
}
let len = databus.values.len();
let len = databus.values.len() as u32;

let array = (len > 0 && matches!(self.current_function.runtime(), RuntimeType::Acir(_)))
.then(|| {
Expand Down Expand Up @@ -223,9 +223,11 @@ impl FunctionBuilder {
ssa_params: &[ValueId],
mut flattened_params_databus_visibility: Vec<DatabusVisibility>,
) -> Vec<DatabusVisibility> {
let ssa_param_sizes: Vec<_> = ssa_params
let ssa_param_sizes: Vec<usize> = ssa_params
.iter()
.map(|ssa_param| self.current_function.dfg[*ssa_param].get_type().flattened_size())
.map(|ssa_param| {
self.current_function.dfg[*ssa_param].get_type().flattened_size() as usize
})
.collect();

let mut is_ssa_params_databus = Vec::with_capacity(ssa_params.len());
Expand Down
30 changes: 7 additions & 23 deletions compiler/noirc_evaluator/src/ssa/ir/dfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,13 +307,13 @@ impl DataFlowGraph {
instruction_id: InstructionId,
ctrl_typevars: Option<Vec<Type>>,
) {
self.results.insert(instruction_id, Default::default());
let result_types = self.instruction_result_types(instruction_id, ctrl_typevars);
let results = vecmap(result_types.into_iter().enumerate(), |(position, typ)| {
let instruction = instruction_id;
self.values.insert(Value::Instruction { typ, position, instruction })
});

// Get all of the types that this instruction produces
// and append them as results.
for typ in self.instruction_result_types(instruction_id, ctrl_typevars) {
self.append_result(instruction_id, typ);
}
self.results.insert(instruction_id, results);
}

/// Return the result types of this instruction.
Expand Down Expand Up @@ -370,22 +370,6 @@ impl DataFlowGraph {
matches!(self.values[value].get_type(), Type::Reference(_))
}

/// Appends a result type to the instruction.
pub(crate) fn append_result(&mut self, instruction_id: InstructionId, typ: Type) -> ValueId {
let results = self.results.get_mut(&instruction_id).unwrap();
let expected_res_position = results.len();

let value_id = self.values.insert(Value::Instruction {
typ,
position: expected_res_position,
instruction: instruction_id,
});

// Add value to the list of results for this instruction
results.push(value_id);
value_id
}

/// Replaces an instruction result with a fresh id.
pub(crate) fn replace_result(
&mut self,
Expand Down Expand Up @@ -463,7 +447,7 @@ impl DataFlowGraph {

/// If this value is an array, return the length of the array as indicated by its type.
/// Otherwise, return None.
pub(crate) fn try_get_array_length(&self, value: ValueId) -> Option<usize> {
pub(crate) fn try_get_array_length(&self, value: ValueId) -> Option<u32> {
match self.type_of_value(value) {
Type::Array(_, length) => Some(length),
_ => None,
Expand Down
14 changes: 7 additions & 7 deletions compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub(super) fn simplify_call(
if let (Some(constant_args), Some(return_type)) = (constant_args, return_type.clone()) {
let field = constant_args[0];
let limb_count = if let Type::Array(_, array_len) = return_type {
array_len as u32
array_len
} else {
unreachable!("ICE: Intrinsic::ToRadix return type must be array")
};
Expand All @@ -73,7 +73,7 @@ pub(super) fn simplify_call(
let field = constant_args[0];
let radix = constant_args[1].to_u128() as u32;
let limb_count = if let Type::Array(_, array_len) = return_type {
array_len as u32
array_len
} else {
unreachable!("ICE: Intrinsic::ToRadix return type must be array")
};
Expand Down Expand Up @@ -361,7 +361,7 @@ pub(super) fn simplify_call(
Intrinsic::IsUnconstrained => SimplifyResult::None,
Intrinsic::DerivePedersenGenerators => {
if let Some(Type::Array(_, len)) = return_type.clone() {
simplify_derive_generators(dfg, arguments, len as u32, block, call_stack)
simplify_derive_generators(dfg, arguments, len, block, call_stack)
} else {
unreachable!("Derive Pedersen Generators must return an array");
}
Expand Down Expand Up @@ -442,8 +442,8 @@ fn simplify_slice_push_back(
for elem in &arguments[2..] {
slice.push_back(*elem);
}
let slice_size = slice.len();
let element_size = element_type.element_size();
let slice_size = slice.len() as u32;
let element_size = element_type.element_size() as u32;
let new_slice = make_array(dfg, slice, element_type, block, &call_stack);

let set_last_slice_value_instr = Instruction::ArraySet {
Expand Down Expand Up @@ -632,7 +632,7 @@ fn make_constant_array(
let result_constants: im::Vector<_> =
results.map(|element| dfg.make_constant(element, typ.clone())).collect();

let typ = Type::Array(Arc::new(vec![typ]), result_constants.len());
let typ = Type::Array(Arc::new(vec![typ]), result_constants.len() as u32);
make_array(dfg, result_constants, typ, block, call_stack)
}

Expand Down Expand Up @@ -819,7 +819,7 @@ fn simplify_derive_generators(
results.push(dfg.make_constant(y, Type::field()));
results.push(is_infinite);
}
let len = results.len();
let len = results.len() as u32;
let typ =
Type::Array(vec![Type::field(), Type::field(), Type::unsigned(1)].into(), len / 3);
let result = make_array(dfg, results.into(), typ, block, call_stack);
Expand Down
6 changes: 3 additions & 3 deletions compiler/noirc_evaluator/src/ssa/ir/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub(crate) enum Type {
Reference(Arc<Type>),

/// An immutable array value with the given element type and length
Array(Arc<CompositeType>, usize),
Array(Arc<CompositeType>, u32),

/// An immutable slice value with a given element type
Slice(Arc<CompositeType>),
Expand Down Expand Up @@ -111,7 +111,7 @@ impl Type {
}

/// Creates the str<N> type, of the given length N
pub(crate) fn str(length: usize) -> Type {
pub(crate) fn str(length: u32) -> Type {
Type::Array(Arc::new(vec![Type::char()]), length)
}

Expand Down Expand Up @@ -161,7 +161,7 @@ impl Type {
}

/// Returns the flattened size of a Type
pub(crate) fn flattened_size(&self) -> usize {
pub(crate) fn flattened_size(&self) -> u32 {
match self {
Type::Array(elements, len) => {
elements.iter().fold(0, |sum, elem| sum + (elem.flattened_size() * len))
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_evaluator/src/ssa/opt/as_slice_length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Function {
}
}

fn known_slice_lengths(func: &Function) -> HashMap<InstructionId, usize> {
fn known_slice_lengths(func: &Function) -> HashMap<InstructionId, u32> {
let mut known_slice_lengths = HashMap::default();
for block_id in func.reachable_blocks() {
let block = &func.dfg[block_id];
Expand Down Expand Up @@ -61,7 +61,7 @@ fn known_slice_lengths(func: &Function) -> HashMap<InstructionId, usize> {

fn replace_known_slice_lengths(
func: &mut Function,
known_slice_lengths: HashMap<InstructionId, usize>,
known_slice_lengths: HashMap<InstructionId, u32>,
) {
known_slice_lengths.into_iter().for_each(|(instruction_id, known_length)| {
let call_returns = func.dfg.instruction_results(instruction_id);
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ pub(crate) fn type_to_brillig_parameter(typ: &Type) -> Option<BrilligParameter>
for item_typ in item_type.iter() {
parameters.push(type_to_brillig_parameter(item_typ)?);
}
Some(BrilligParameter::Array(parameters, *size))
Some(BrilligParameter::Array(parameters, *size as usize))
}
_ => None,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl<'a> SliceCapacityTracker<'a> {
pub(crate) fn collect_slice_information(
&self,
instruction: &Instruction,
slice_sizes: &mut HashMap<ValueId, usize>,
slice_sizes: &mut HashMap<ValueId, u32>,
results: &[ValueId],
) {
match instruction {
Expand Down Expand Up @@ -106,13 +106,12 @@ impl<'a> SliceCapacityTracker<'a> {
Intrinsic::ToBits(_) => {
// Compiler sanity check
assert!(matches!(self.dfg.type_of_value(result_slice), Type::Slice(_)));
slice_sizes.insert(result_slice, FieldElement::max_num_bits() as usize);
slice_sizes.insert(result_slice, FieldElement::max_num_bits());
}
Intrinsic::ToRadix(_) => {
// Compiler sanity check
assert!(matches!(self.dfg.type_of_value(result_slice), Type::Slice(_)));
slice_sizes
.insert(result_slice, FieldElement::max_num_bytes() as usize);
slice_sizes.insert(result_slice, FieldElement::max_num_bytes());
}
Intrinsic::AsSlice => {
let array_size = self
Expand Down Expand Up @@ -157,15 +156,15 @@ impl<'a> SliceCapacityTracker<'a> {
pub(crate) fn compute_slice_capacity(
&self,
array_id: ValueId,
slice_sizes: &mut HashMap<ValueId, usize>,
slice_sizes: &mut HashMap<ValueId, u32>,
) {
if let Some((array, typ)) = self.dfg.get_array_constant(array_id) {
// Compiler sanity check
assert!(!typ.is_nested_slice(), "ICE: Nested slices are not allowed and should not have reached the flattening pass of SSA");
if let Type::Slice(_) = typ {
let element_size = typ.element_size();
let len = array.len() / element_size;
slice_sizes.insert(array_id, len);
slice_sizes.insert(array_id, len as u32);
}
}
}
Expand Down
Loading

0 comments on commit 6196d05

Please sign in to comment.