Skip to content

Commit

Permalink
fix: handle nested arrays in calldata (noir-lang/noir#6232)
Browse files Browse the repository at this point in the history
feat: add more `Type` and `UnresolvedType` methods (noir-lang/noir#5994)
fix: Panic on composite types within databus (noir-lang/noir#6225)
feat(perf): Follow array sets backwards in array set from get optimization (noir-lang/noir#6208)
fix: check for Schnorr null signature (noir-lang/noir#6226)
  • Loading branch information
AztecBot committed Oct 7, 2024
2 parents 484b386 + 1cb2abd commit 4ce6453
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 86 deletions.
2 changes: 1 addition & 1 deletion .noir-sync-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8236cbdff60c1aaf41fc53142b6f0f9ea2fc2fa8
0ab8f5e3c32af05a3c158562c0fcf9729741e0ab
47 changes: 31 additions & 16 deletions noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,29 @@ impl<'a> Context<'a> {
}
}

/// Returns the acir value at the provided databus offset
fn get_from_call_data(
&mut self,
offset: &mut AcirVar,
call_data_block: BlockId,
typ: &Type,
) -> Result<AcirValue, RuntimeError> {
match typ {
Type::Numeric(_) => self.array_get_value(&Type::field(), call_data_block, offset),
Type::Array(arc, len) => {
let mut result = Vector::new();
for _i in 0..*len {
for sub_type in arc.iter() {
let element = self.get_from_call_data(offset, call_data_block, sub_type)?;
result.push_back(element);
}
}
Ok(AcirValue::Array(result))
}
_ => unimplemented!("Unsupported type in databus"),
}
}

/// Generates a read opcode for the array
/// `index_side_effect == false` means that we ensured `var_index` will have a type matching the value in the array
fn array_get(
Expand All @@ -1316,27 +1339,19 @@ impl<'a> Context<'a> {
let block_id = self.ensure_array_is_initialized(array, dfg)?;
let results = dfg.instruction_results(instruction);
let res_typ = dfg.type_of_value(results[0]);

// Get operations to call-data parameters are replaced by a get to the call-data-bus array
if let Some(call_data) =
self.data_bus.call_data.iter().find(|cd| cd.index_map.contains_key(&array))
{
let type_size = res_typ.flattened_size();
let type_size = self.acir_context.add_constant(FieldElement::from(type_size as i128));
let offset = self.acir_context.mul_var(var_index, type_size)?;
let call_data =
self.data_bus.call_data.iter().find(|cd| cd.index_map.contains_key(&array)).cloned();
if let Some(call_data) = call_data {
let call_data_block = self.ensure_array_is_initialized(call_data.array_id, dfg)?;
let bus_index = self
.acir_context
.add_constant(FieldElement::from(call_data.index_map[&array] as i128));
let new_index = self.acir_context.add_var(offset, bus_index)?;
return self.array_get(
instruction,
call_data.array_id,
new_index,
dfg,
index_side_effect,
);
let mut current_index = self.acir_context.add_var(bus_index, var_index)?;
let result = self.get_from_call_data(&mut current_index, call_data_block, &res_typ)?;
self.define_result(dfg, instruction, result.clone());
return Ok(result);
}

// Compiler sanity check
assert!(
!res_typ.contains_slice_element(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,21 @@ impl FunctionBuilder {
}
Type::Array(typ, len) => {
databus.map.insert(value, databus.index);
for i in 0..len {
for (subitem_index, subitem_typ) in typ.iter().enumerate() {
let index = i * typ.len() + subitem_index;
// load each element of the array
let index = self

let mut index = 0;
for _i in 0..len {
for subitem_typ in typ.iter() {
// load each element of the array, and add it to the databus
let index_var = self
.current_function
.dfg
.make_constant(FieldElement::from(index as i128), Type::length_type());
let element = self.insert_array_get(value, index, subitem_typ.clone());
let element = self.insert_array_get(value, index_var, subitem_typ.clone());
index += match subitem_typ {
Type::Array(_, _) | Type::Slice(_) => subitem_typ.element_size(),
Type::Numeric(_) => 1,
_ => unreachable!("Unsupported type for databus"),
};
self.add_to_data_bus(element, databus);
}
}
Expand Down
44 changes: 22 additions & 22 deletions noir/noir-repo/noir_stdlib/src/meta/typ.nr
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,47 @@ use crate::option::Option;
/// against another type it will also be set to that type. For example, if `a` is a type
/// variable and we have the type equality `(a, i32) = (u8, i32)`, the compiler will set
/// `a` equal to `u8`.
///
///
/// Unbound type variables will often be rendered as `_` while printing them. Bound type
/// variables will appear as the type they are bound to.
///
///
/// This can be used in conjunction with functions which internally perform type checks
/// such as `Type::implements` or `Type::get_trait_impl` to potentially grab some of the types used.
///
///
/// Note that calling `Type::implements` or `Type::get_trait_impl` on a type variable will always
/// fail.
///
///
/// Example:
///
///
/// ```noir
/// trait Serialize<let N: u32> {}
///
///
/// impl Serialize<1> for Field {}
///
///
/// impl<T, let N: u32, let M: u32> Serialize<N * M> for [T; N]
/// where T: Serialize<M> {}
///
///
/// impl<T, U, let N: u32, let M: u32> Serialize<N + M> for (T, U)
/// where T: Serialize<N>, U: Serialize<M> {}
///
///
/// fn fresh_variable_example() {
/// let typevar1 = std::meta::typ::fresh_type_variable();
/// let constraint = quote { Serialize<$typevar1> }.as_trait_constraint();
/// let field_type = quote { Field }.as_type();
///
///
/// // Search for a trait impl (binding typevar1 to 1 when the impl is found):
/// assert(field_type.implements(constraint));
///
///
/// // typevar1 should be bound to the "1" generic now:
/// assert_eq(typevar1.as_constant().unwrap(), 1);
///
///
/// // If we want to do the same with a different type, we need to
/// // create a new type variable now that `typevar1` is bound
/// let typevar2 = std::meta::typ::fresh_type_variable();
/// let constraint = quote { Serialize<$typevar2> }.as_trait_constraint();
/// let array_type = quote { [(Field, Field); 5] }.as_type();
/// assert(array_type.implements(constraint));
///
///
/// // Now typevar2 should be bound to the serialized pair size 2 times the array length 5
/// assert_eq(typevar2.as_constant().unwrap(), 10);
/// }
Expand All @@ -60,14 +60,14 @@ pub comptime fn fresh_type_variable() -> Type {}

impl Type {
/// If this type is an array, return a pair of (element type, size type).
///
///
/// Example:
///
///
/// ```noir
/// comptime {
/// let array_type = quote { [Field; 3] }.as_type();
/// let (field_type, three_type) = array_type.as_array().unwrap();
///
///
/// assert(field_type.is_field());
/// assert_eq(three_type.as_constant().unwrap(), 3);
/// }
Expand Down Expand Up @@ -127,14 +127,14 @@ impl Type {
/// for a trait constraint specified from a `where` clause is unknown,
/// this function will return `None` in these cases. If you only want to know
/// whether a type implements a trait, use `implements` instead.
///
///
/// Example:
///
///
/// ```rust
/// comptime {
/// let field_type = quote { Field }.as_type();
/// let default = quote { Default }.as_trait_constraint();
///
///
/// let the_impl: TraitImpl = field_type.get_trait_impl(default).unwrap();
/// assert(the_impl.methods().len(), 1);
/// }
Expand All @@ -147,16 +147,16 @@ impl Type {
/// Returns `true` if this type implements the given trait. Note that unlike
/// `get_trait_impl` this will also return true for any `where` constraints
/// in scope.
///
///
/// Example:
///
///
/// ```rust
/// fn foo<T>() where T: Default {
/// comptime {
/// let field_type = quote { Field }.as_type();
/// let default = quote { Default }.as_trait_constraint();
/// assert(field_type.implements(default));
///
///
/// let t = quote { T }.as_type();
/// assert(t.implements(default));
/// }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
zero = "0"
one = "1"
values = [[["12", "33"], ["37", "11"]],[["14", "37"], ["30", "10"]],[["10", "30"], ["30", "10"]]]

[[foos]]
x = "27"
y = "40"
x = 1
y = [1,2,3,4,5,6,7,8,9,0]

[[foos]]
x = "28"
y = "42"
x = 2
y = [1,2,3,5,6,8,7,8,9,0]
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
struct Foo {
x: u32,
y: u32,
y: [u32; 10],
}

fn main(foos: call_data(0) [Foo; 2], zero: u32, one: u32) -> return_data u32 {
fn main(
foos: call_data(0) [Foo; 2],
values: call_data(0) [[[u32; 2]; 2]; 3],
zero: u32,
one: u32
) -> pub u32 {
assert_eq(foos[zero].x + 1, foos[one].x);
assert_eq(foos[zero].y + 2, foos[one].y);
foos[zero].x + foos[one].y
assert_eq(foos[zero].y[3] + 2, foos[one].y[4]);
assert_eq(values[zero][one][zero], values[one][zero][one]);
foos[zero].x + foos[one].y[0]
}

This file was deleted.

This file was deleted.

This file was deleted.

0 comments on commit 4ce6453

Please sign in to comment.