diff --git a/.noir-sync-commit b/.noir-sync-commit index cd2a6b9708e..5da2a40a0aa 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -f03f8aed34393f7b0f6f68a189ce6c6192f6af6e +69eca9b8671fa54192bef814dd584fdb5387a5f7 \ No newline at end of file diff --git a/noir/noir-repo/acvm-repo/brillig_vm/src/memory.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/memory.rs index 4092cd06ae0..6c6b5968cd7 100644 --- a/noir/noir-repo/acvm-repo/brillig_vm/src/memory.rs +++ b/noir/noir-repo/acvm-repo/brillig_vm/src/memory.rs @@ -294,6 +294,12 @@ impl Memory { } pub fn read_slice(&self, addr: MemoryAddress, len: usize) -> &[MemoryValue] { + // Allows to read a slice of uninitialized memory if the length is zero. + // Ideally we'd be able to read uninitialized memory in general (as read does) + // but that's not possible if we want to return a slice instead of owned data. + if len == 0 { + return &[]; + } &self.inner[addr.to_usize()..(addr.to_usize() + len)] } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs index d38601bfc1b..80a63f223e7 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs @@ -58,8 +58,9 @@ pub(crate) fn optimize_into_acir( let ssa = SsaBuilder::new(program, print_passes, force_brillig_output, print_timings)? .run_pass(Ssa::defunctionalize, "After Defunctionalization:") .run_pass(Ssa::remove_paired_rc, "After Removing Paired rc_inc & rc_decs:") - .run_pass(Ssa::inline_functions, "After Inlining:") + .run_pass(Ssa::separate_runtime, "After Runtime Separation:") .run_pass(Ssa::resolve_is_unconstrained, "After Resolving IsUnconstrained:") + .run_pass(Ssa::inline_functions, "After Inlining:") // Run mem2reg with the CFG separated into blocks .run_pass(Ssa::mem2reg, "After Mem2Reg:") .run_pass(Ssa::as_slice_optimization, "After `as_slice` optimization") diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 545827df1c5..f763ae52d50 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -22,7 +22,7 @@ use noirc_errors::Location; /// its blocks, instructions, and values. This struct is largely responsible for /// owning most data in a function and handing out Ids to this data that can be /// shared without worrying about ownership. -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub(crate) struct DataFlowGraph { /// All of the instructions in a function instructions: DenseMap, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs index a49e02b0380..c44824b464b 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs @@ -64,6 +64,13 @@ impl Function { Self { name, id, entry_block, dfg, runtime: RuntimeType::Acir(InlineType::default()) } } + /// Creates a new function as a clone of the one passed in with the passed in id. + pub(crate) fn clone_with_id(id: FunctionId, another: &Function) -> Self { + let dfg = another.dfg.clone(); + let entry_block = another.entry_block; + Self { name: another.name.clone(), id, entry_block, dfg, runtime: another.runtime } + } + /// The name of the function. /// Used exclusively for debugging purposes. pub(crate) fn name(&self) -> &str { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/map.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/map.rs index b6055973f1c..3c3feabc390 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/map.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/map.rs @@ -115,7 +115,7 @@ impl std::fmt::Display for Id { /// access to indices is provided. Since IDs must be stable and correspond /// to indices in the internal Vec, operations that would change element /// ordering like pop, remove, swap_remove, etc, are not possible. -#[derive(Debug)] +#[derive(Debug, Clone)] pub(crate) struct DenseMap { storage: Vec, } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index 1293671da50..e2a7f51d0a0 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -27,7 +27,7 @@ const RECURSION_LIMIT: u32 = 1000; impl Ssa { /// Inline all functions within the IR. /// - /// In the case of recursive functions, this will attempt + /// In the case of recursive Acir functions, this will attempt /// to recursively inline until the RECURSION_LIMIT is reached. /// /// Functions are recursively inlined into main until either we finish @@ -41,6 +41,8 @@ impl Ssa { /// There are some attributes that allow inlining a function at a different step of codegen. /// Currently this is just `InlineType::NoPredicates` for which we have a flag indicating /// whether treating that inline functions. The default is to treat these functions as entry points. + /// + /// This step should run after runtime separation, since it relies on the runtime of the called functions being final. #[tracing::instrument(level = "trace", skip(self))] pub(crate) fn inline_functions(self) -> Ssa { Self::inline_functions_inner(self, true) @@ -52,12 +54,17 @@ impl Ssa { } fn inline_functions_inner(mut self, no_predicates_is_entry_point: bool) -> Ssa { + let recursive_functions = find_all_recursive_functions(&self); self.functions = btree_map( - get_entry_point_functions(&self, no_predicates_is_entry_point), + get_functions_to_inline_into(&self, no_predicates_is_entry_point), |entry_point| { - let new_function = - InlineContext::new(&self, entry_point, no_predicates_is_entry_point) - .inline_all(&self); + let new_function = InlineContext::new( + &self, + entry_point, + no_predicates_is_entry_point, + recursive_functions.clone(), + ) + .inline_all(&self); (entry_point, new_function) }, ); @@ -80,6 +87,8 @@ struct InlineContext { entry_point: FunctionId, no_predicates_is_entry_point: bool, + // We keep track of the recursive functions in the SSA to avoid inlining them in a brillig context. + recursive_functions: BTreeSet, } /// The per-function inlining context contains information that is only valid for one function. @@ -113,28 +122,101 @@ struct PerFunctionContext<'function> { inlining_entry: bool, } -/// The entry point functions are each function we should inline into - and each function that -/// should be left in the final program. -/// This is the `main` function, any Acir functions with a [fold inline type][InlineType::Fold], -/// and any brillig functions used. -fn get_entry_point_functions( +/// Utility function to find out the direct calls of a function. +fn called_functions(func: &Function) -> BTreeSet { + let mut called_function_ids = BTreeSet::default(); + for block_id in func.reachable_blocks() { + for instruction_id in func.dfg[block_id].instructions() { + let Instruction::Call { func: called_value_id, .. } = &func.dfg[*instruction_id] else { + continue; + }; + + if let Value::Function(function_id) = func.dfg[*called_value_id] { + called_function_ids.insert(function_id); + } + } + } + + called_function_ids +} + +// Recursively explore the SSA to find the functions that end up calling themselves +fn find_recursive_functions( + ssa: &Ssa, + current_function: FunctionId, + mut explored_functions: im::HashSet, + recursive_functions: &mut BTreeSet, +) { + if explored_functions.contains(¤t_function) { + recursive_functions.insert(current_function); + return; + } + + let called_functions = called_functions(&ssa.functions[¤t_function]); + + explored_functions.insert(current_function); + + for called_function in called_functions { + find_recursive_functions( + ssa, + called_function, + explored_functions.clone(), + recursive_functions, + ); + } +} + +fn find_all_recursive_functions(ssa: &Ssa) -> BTreeSet { + let mut recursive_functions = BTreeSet::default(); + find_recursive_functions(ssa, ssa.main_id, im::HashSet::default(), &mut recursive_functions); + recursive_functions +} + +/// The functions we should inline into (and that should be left in the final program) are: +/// - main +/// - Any Brillig function called from Acir +/// - Any Brillig recursive function (Acir recursive functions will be inlined into the main function) +/// - Any Acir functions with a [fold inline type][InlineType::Fold], +fn get_functions_to_inline_into( ssa: &Ssa, no_predicates_is_entry_point: bool, ) -> BTreeSet { - let functions = ssa.functions.iter(); - let mut entry_points = functions - .filter(|(_, function)| { - // If we have not already finished the flattening pass, functions marked - // to not have predicates should be marked as entry points. - let no_predicates_is_entry_point = - no_predicates_is_entry_point && function.is_no_predicates(); - function.runtime().is_entry_point() || no_predicates_is_entry_point + let mut brillig_entry_points = BTreeSet::default(); + let mut acir_entry_points = BTreeSet::default(); + + for (func_id, function) in ssa.functions.iter() { + if function.runtime() == RuntimeType::Brillig { + continue; + } + + // If we have not already finished the flattening pass, functions marked + // to not have predicates should be marked as entry points. + let no_predicates_is_entry_point = + no_predicates_is_entry_point && function.is_no_predicates(); + if function.runtime().is_entry_point() || no_predicates_is_entry_point { + acir_entry_points.insert(*func_id); + } + + for called_function_id in called_functions(function) { + if ssa.functions[&called_function_id].runtime() == RuntimeType::Brillig { + brillig_entry_points.insert(called_function_id); + } + } + } + + let brillig_recursive_functions: BTreeSet<_> = find_all_recursive_functions(ssa) + .into_iter() + .filter(|recursive_function_id| { + let function = &ssa.functions[&recursive_function_id]; + function.runtime() == RuntimeType::Brillig }) - .map(|(id, _)| *id) - .collect::>(); + .collect(); - entry_points.insert(ssa.main_id); - entry_points + std::iter::once(ssa.main_id) + .chain(acir_entry_points) + .chain(brillig_entry_points) + .chain(brillig_recursive_functions) + .collect() } impl InlineContext { @@ -147,6 +229,7 @@ impl InlineContext { ssa: &Ssa, entry_point: FunctionId, no_predicates_is_entry_point: bool, + recursive_functions: BTreeSet, ) -> InlineContext { let source = &ssa.functions[&entry_point]; let mut builder = FunctionBuilder::new(source.name().to_owned(), entry_point); @@ -157,6 +240,7 @@ impl InlineContext { entry_point, call_stack: CallStack::new(), no_predicates_is_entry_point, + recursive_functions, } } @@ -391,18 +475,10 @@ impl<'function> PerFunctionContext<'function> { match &self.source_function.dfg[*id] { Instruction::Call { func, arguments } => match self.get_function(*func) { Some(func_id) => { - let function = &ssa.functions[&func_id]; - // If we have not already finished the flattening pass, functions marked - // to not have predicates should be marked as entry points unless we are inlining into brillig. - let entry_point = &ssa.functions[&self.context.entry_point]; - let no_predicates_is_entry_point = - self.context.no_predicates_is_entry_point - && function.is_no_predicates() - && !matches!(entry_point.runtime(), RuntimeType::Brillig); - if function.runtime().is_entry_point() || no_predicates_is_entry_point { - self.push_instruction(*id); - } else { + if self.should_inline_call(ssa, func_id) { self.inline_function(ssa, *id, func_id, arguments); + } else { + self.push_instruction(*id); } } None => self.push_instruction(*id), @@ -412,6 +488,24 @@ impl<'function> PerFunctionContext<'function> { } } + fn should_inline_call(&self, ssa: &Ssa, called_func_id: FunctionId) -> bool { + let function = &ssa.functions[&called_func_id]; + + if let RuntimeType::Acir(inline_type) = function.runtime() { + // If the called function is acir, we inline if it's not an entry point + + // If we have not already finished the flattening pass, functions marked + // to not have predicates should be marked as entry points. + let no_predicates_is_entry_point = + self.context.no_predicates_is_entry_point && function.is_no_predicates(); + !inline_type.is_entry_point() && !no_predicates_is_entry_point + } else { + // If the called function is brillig, we inline only if it's into brillig and the function is not recursive + ssa.functions[&self.context.entry_point].runtime() == RuntimeType::Brillig + && !self.context.recursive_functions.contains(&called_func_id) + } + } + /// Inline a function call and remember the inlined return values in the values map fn inline_function( &mut self, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs index f6c3f022bfc..4e5fa262696 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs @@ -18,5 +18,6 @@ mod remove_bit_shifts; mod remove_enable_side_effects; mod remove_if_else; mod resolve_is_unconstrained; +mod runtime_separation; mod simplify_cfg; mod unrolling; diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/runtime_separation.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/runtime_separation.rs new file mode 100644 index 00000000000..c0c9c0a1372 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/runtime_separation.rs @@ -0,0 +1,348 @@ +use std::collections::BTreeSet; + +use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; + +use crate::ssa::{ + ir::{ + function::{Function, FunctionId, RuntimeType}, + instruction::Instruction, + value::{Value, ValueId}, + }, + ssa_gen::Ssa, +}; + +impl Ssa { + /// This optimization step separates the runtime of the functions in the SSA. + /// After this step, all functions with runtime `Acir` will be converted to Acir and + /// the functions with runtime `Brillig` will be converted to Brillig. + /// It does so by cloning all ACIR functions called from a Brillig context + /// and changing the runtime of the cloned functions to Brillig. + /// This pass needs to run after functions as values have been resolved (defunctionalization). + #[tracing::instrument(level = "trace", skip(self))] + pub(crate) fn separate_runtime(mut self) -> Self { + RuntimeSeparatorContext::separate_runtime(&mut self); + self + } +} + +#[derive(Debug, Default)] +struct RuntimeSeparatorContext { + // Original functions to clone to brillig + acir_functions_called_from_brillig: BTreeSet, + // Tracks the original => cloned version + mapped_functions: HashMap, +} + +impl RuntimeSeparatorContext { + pub(crate) fn separate_runtime(ssa: &mut Ssa) { + let mut runtime_separator = RuntimeSeparatorContext::default(); + + // We first collect all the acir functions called from a brillig context by exploring the SSA recursively + let mut processed_functions = HashSet::default(); + runtime_separator.collect_acir_functions_called_from_brillig( + ssa, + ssa.main_id, + false, + &mut processed_functions, + ); + + // Now we clone the relevant acir functions and change their runtime to brillig + runtime_separator.convert_acir_functions_called_from_brillig_to_brillig(ssa); + + // Now we update any calls within a brillig context to the mapped functions + runtime_separator.replace_calls_to_mapped_functions(ssa); + + // Some functions might be unreachable now (for example an acir function only called from brillig) + prune_unreachable_functions(ssa); + } + + fn collect_acir_functions_called_from_brillig( + &mut self, + ssa: &Ssa, + current_func_id: FunctionId, + mut within_brillig: bool, + processed_functions: &mut HashSet<(/* within_brillig */ bool, FunctionId)>, + ) { + // Processed functions needs the within brillig flag, since it is possible to call the same function from both brillig and acir + if processed_functions.contains(&(within_brillig, current_func_id)) { + return; + } + processed_functions.insert((within_brillig, current_func_id)); + + let func = &ssa.functions[¤t_func_id]; + if func.runtime() == RuntimeType::Brillig { + within_brillig = true; + } + + let called_functions = called_functions(func); + + if within_brillig { + for called_func_id in called_functions.iter() { + let called_func = &ssa.functions[&called_func_id]; + if matches!(called_func.runtime(), RuntimeType::Acir(_)) { + self.acir_functions_called_from_brillig.insert(*called_func_id); + } + } + } + + for called_func_id in called_functions.into_iter() { + self.collect_acir_functions_called_from_brillig( + ssa, + called_func_id, + within_brillig, + processed_functions, + ); + } + } + + fn convert_acir_functions_called_from_brillig_to_brillig(&mut self, ssa: &mut Ssa) { + for acir_func_id in self.acir_functions_called_from_brillig.iter() { + let cloned_id = ssa.clone_fn(*acir_func_id); + let new_func = + ssa.functions.get_mut(&cloned_id).expect("Cloned function should exist in SSA"); + new_func.set_runtime(RuntimeType::Brillig); + self.mapped_functions.insert(*acir_func_id, cloned_id); + } + } + + fn replace_calls_to_mapped_functions(&self, ssa: &mut Ssa) { + for (_function_id, func) in ssa.functions.iter_mut() { + if func.runtime() == RuntimeType::Brillig { + for called_func_value_id in called_functions_values(func).iter() { + let Value::Function(called_func_id) = &func.dfg[*called_func_value_id] else { + unreachable!("Value should be a function") + }; + if let Some(mapped_func_id) = self.mapped_functions.get(called_func_id) { + let mapped_value_id = func.dfg.import_function(*mapped_func_id); + func.dfg.set_value_from_id(*called_func_value_id, mapped_value_id); + } + } + } + } + } +} + +// We only consider direct calls to functions since functions as values should have been resolved +fn called_functions_values(func: &Function) -> BTreeSet { + let mut called_function_ids = BTreeSet::default(); + for block_id in func.reachable_blocks() { + for instruction_id in func.dfg[block_id].instructions() { + let Instruction::Call { func: called_value_id, .. } = &func.dfg[*instruction_id] else { + continue; + }; + + if let Value::Function(_) = func.dfg[*called_value_id] { + called_function_ids.insert(*called_value_id); + } + } + } + + called_function_ids +} + +fn called_functions(func: &Function) -> BTreeSet { + called_functions_values(func) + .into_iter() + .map(|value_id| { + let Value::Function(func_id) = func.dfg[value_id] else { + unreachable!("Value should be a function") + }; + func_id + }) + .collect() +} + +fn collect_reachable_functions( + ssa: &Ssa, + current_func_id: FunctionId, + reachable_functions: &mut HashSet, +) { + if reachable_functions.contains(¤t_func_id) { + return; + } + reachable_functions.insert(current_func_id); + + let func = &ssa.functions[¤t_func_id]; + let called_functions = called_functions(func); + + for called_func_id in called_functions.iter() { + collect_reachable_functions(ssa, *called_func_id, reachable_functions); + } +} + +fn prune_unreachable_functions(ssa: &mut Ssa) { + let mut reachable_functions = HashSet::default(); + collect_reachable_functions(ssa, ssa.main_id, &mut reachable_functions); + + ssa.functions.retain(|id, _value| reachable_functions.contains(id)); +} + +#[cfg(test)] +mod test { + use std::collections::BTreeSet; + + use noirc_frontend::monomorphization::ast::InlineType; + + use crate::ssa::{ + function_builder::FunctionBuilder, + ir::{ + function::{Function, FunctionId, RuntimeType}, + map::Id, + types::Type, + }, + opt::runtime_separation::called_functions, + ssa_gen::Ssa, + }; + + #[test] + fn basic_runtime_separation() { + // brillig fn foo { + // b0(): + // v0 = call bar() + // return v0 + // } + // acir fn bar { + // b0(): + // return 72 + // } + let foo_id = Id::test_new(0); + let mut builder = FunctionBuilder::new("foo".into(), foo_id); + builder.current_function.set_runtime(RuntimeType::Brillig); + + let bar_id = Id::test_new(1); + let bar = builder.import_function(bar_id); + let results = builder.insert_call(bar, Vec::new(), vec![Type::field()]).to_vec(); + builder.terminate_with_return(results); + + builder.new_function("bar".into(), bar_id, InlineType::default()); + let expected_return = 72u128; + let seventy_two = builder.field_constant(expected_return); + builder.terminate_with_return(vec![seventy_two]); + + let ssa = builder.finish(); + assert_eq!(ssa.functions.len(), 2); + + // Expected result + // brillig fn foo { + // b0(): + // v0 = call bar() + // return v0 + // } + // brillig fn bar { + // b0(): + // return 72 + // } + let separated = ssa.separate_runtime(); + + // The original bar function must have been pruned + assert_eq!(separated.functions.len(), 2); + + // All functions should be brillig now + for func in separated.functions.values() { + assert_eq!(func.runtime(), RuntimeType::Brillig); + } + } + + fn find_func_by_name<'ssa>( + ssa: &'ssa Ssa, + funcs: &BTreeSet, + name: &str, + ) -> &'ssa Function { + funcs + .iter() + .find_map(|id| { + let func = ssa.functions.get(id).unwrap(); + if func.name() == name { + Some(func) + } else { + None + } + }) + .unwrap() + } + + #[test] + fn same_function_shared_acir_brillig() { + // acir fn foo { + // b0(): + // v0 = call bar() + // v1 = call baz() + // return v0, v1 + // } + // brillig fn bar { + // b0(): + // v0 = call baz() + // return v0 + // } + // acir fn baz { + // b0(): + // return 72 + // } + let foo_id = Id::test_new(0); + let mut builder = FunctionBuilder::new("foo".into(), foo_id); + + let bar_id = Id::test_new(1); + let baz_id = Id::test_new(2); + let bar = builder.import_function(bar_id); + let baz = builder.import_function(baz_id); + let v0 = builder.insert_call(bar, Vec::new(), vec![Type::field()]).to_vec(); + let v1 = builder.insert_call(baz, Vec::new(), vec![Type::field()]).to_vec(); + builder.terminate_with_return(vec![v0[0], v1[0]]); + + builder.new_brillig_function("bar".into(), bar_id); + let baz = builder.import_function(baz_id); + let v0 = builder.insert_call(baz, Vec::new(), vec![Type::field()]).to_vec(); + builder.terminate_with_return(v0); + + builder.new_function("baz".into(), baz_id, InlineType::default()); + let expected_return = 72u128; + let seventy_two = builder.field_constant(expected_return); + builder.terminate_with_return(vec![seventy_two]); + + let ssa = builder.finish(); + assert_eq!(ssa.functions.len(), 3); + + // Expected result + // acir fn foo { + // b0(): + // v0 = call bar() + // v1 = call baz() <- baz_acir + // return v0, v1 + // } + // brillig fn bar { + // b0(): + // v0 = call baz() <- baz_brillig + // return v0 + // } + // acir fn baz { + // b0(): + // return 72 + // } + // brillig fn baz { + // b0(): + // return 72 + // } + let separated = ssa.separate_runtime(); + + // The original baz function must have been duplicated + assert_eq!(separated.functions.len(), 4); + + let main_function = separated.functions.get(&separated.main_id).unwrap(); + assert_eq!(main_function.runtime(), RuntimeType::Acir(InlineType::Inline)); + + let main_calls = called_functions(main_function); + assert_eq!(main_calls.len(), 2); + + let bar = find_func_by_name(&separated, &main_calls, "bar"); + let baz_acir = find_func_by_name(&separated, &main_calls, "baz"); + + assert_eq!(baz_acir.runtime(), RuntimeType::Acir(InlineType::Inline)); + assert_eq!(bar.runtime(), RuntimeType::Brillig); + + let bar_calls = called_functions(bar); + assert_eq!(bar_calls.len(), 1); + + let baz_brillig = find_func_by_name(&separated, &bar_calls, "baz"); + assert_eq!(baz_brillig.runtime(), RuntimeType::Brillig); + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs index 21178c55c73..7a77aa76101 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs @@ -80,6 +80,14 @@ impl Ssa { self.functions.insert(new_id, function); new_id } + + /// Clones an already existing function with a fresh id + pub(crate) fn clone_fn(&mut self, existing_function_id: FunctionId) -> FunctionId { + let new_id = self.next_id.next(); + let function = Function::clone_with_id(new_id, &self.functions[&existing_function_id]); + self.functions.insert(new_id, function); + new_id + } } impl Display for Ssa { diff --git a/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/Nargo.toml b/noir/noir-repo/test_programs/execution_success/acir_inside_brillig_recursion/Nargo.toml similarity index 58% rename from noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/acir_inside_brillig_recursion/Nargo.toml index b92e11d6383..462532bb484 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/Nargo.toml +++ b/noir/noir-repo/test_programs/execution_success/acir_inside_brillig_recursion/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "brillig_embedded_curve" +name = "acir_inside_brillig_recursion" type = "bin" authors = [""] diff --git a/noir/noir-repo/test_programs/execution_success/acir_inside_brillig_recursion/Prover.toml b/noir/noir-repo/test_programs/execution_success/acir_inside_brillig_recursion/Prover.toml new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/acir_inside_brillig_recursion/Prover.toml @@ -0,0 +1 @@ + diff --git a/noir/noir-repo/test_programs/execution_success/acir_inside_brillig_recursion/src/main.nr b/noir/noir-repo/test_programs/execution_success/acir_inside_brillig_recursion/src/main.nr new file mode 100644 index 00000000000..92f8524a771 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/acir_inside_brillig_recursion/src/main.nr @@ -0,0 +1,15 @@ +fn main() { + assert_eq(fibonacci(3), fibonacci_hint(3)); +} + +unconstrained fn fibonacci_hint(x: u32) -> u32 { + fibonacci(x) +} + +fn fibonacci(x: u32) -> u32 { + if x <= 1 { + x + } else { + fibonacci(x - 1) + fibonacci(x - 2) + } +} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_array_eq/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_array_eq/Prover.toml deleted file mode 100644 index ecfed7de213..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_array_eq/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -a = [77,75,108,209,54,16,50,202,155,210,174,185,217,0,170,77,69,217,234,216,10,201,66,51,116,196,81,167,37,77,7,102] -b = [77,75,108,209,54,16,50,202,155,210,174,185,217,0,170,77,69,217,234,216,10,201,66,51,116,196,81,167,37,77,7,102] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_array_eq/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_array_eq/src/main.nr deleted file mode 100644 index 90f631dbed8..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_array_eq/src/main.nr +++ /dev/null @@ -1,4 +0,0 @@ -// Simple example of checking where two arrays are equal -unconstrained fn main(a: [Field; 32], b: [Field; 32]) { - assert(a == b); -} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml deleted file mode 100644 index ed8200d8a95..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "brillig_bit_shifts_runtime" -type = "bin" -authors = [""] - -[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml deleted file mode 100644 index 98d8630792e..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = 64 -y = 1 \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr deleted file mode 100644 index cdeaad7514c..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr +++ /dev/null @@ -1,20 +0,0 @@ -unconstrained fn main(x: u64, y: u8) { - // runtime shifts on compile-time known values - assert(64 as u32 << y == 128); - assert(64 as u32 >> y == 32); - // runtime shifts on runtime values - assert(x << y == 128); - assert(x >> y == 32); - - // Bit-shift with signed integers - let mut a :i8 = y as i8; - let mut b: i8 = x as i8; - assert(b << 1 == -128); - assert(b >> 2 == 16); - assert(b >> y == 32); - a = -a; - assert(a << 7 == -128); - assert(a << y == -2); - - assert(x >> (x as u8) == 0); -} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/Prover.toml deleted file mode 100644 index 7113b9cd038..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/Prover.toml +++ /dev/null @@ -1,3 +0,0 @@ -priv_key = "1" -pub_x = "0x0000000000000000000000000000000000000000000000000000000000000001" -pub_y = "0x0000000000000002cf135e7506a45d632d270d45f1181294833fc48d823f272c" \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/src/main.nr deleted file mode 100644 index 89a699448dc..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_embedded_curve/src/main.nr +++ /dev/null @@ -1,24 +0,0 @@ -use dep::std; - -unconstrained fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { - let g1_y = 17631683881184975370165255887551781615748388533673675138860; - let g1 = std::embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: g1_y, is_infinite: false }; - let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 }; - // Test that multi_scalar_mul correctly derives the public key - let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]); - assert(res[0] == pub_x); - assert(res[1] == pub_y); - - // Test that double function calling embedded_curve_add works as expected - let pub_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false }; - let res = pub_point.double(); - let double = g1.add(g1); - - assert(double.x == res.x); - - // Test calling multi_scalar_mul with multiple points and scalars - let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]); - - // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice - assert(double.x == res[0]); -} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_schnorr/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_schnorr/Prover.toml deleted file mode 100644 index 2faf2018e07..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_schnorr/Prover.toml +++ /dev/null @@ -1,70 +0,0 @@ -message = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] -message_field = "0x010203040506070809" -pub_key_x = "0x04b260954662e97f00cab9adb773a259097f7a274b83b113532bce27fa3fb96a" -pub_key_y = "0x2fd51571db6c08666b0edfbfbc57d432068bccd0110a39b166ab243da0037197" -signature = [ - 1, - 13, - 119, - 112, - 212, - 39, - 233, - 41, - 84, - 235, - 255, - 93, - 245, - 172, - 186, - 83, - 157, - 253, - 76, - 77, - 33, - 128, - 178, - 15, - 214, - 67, - 105, - 107, - 177, - 234, - 77, - 48, - 27, - 237, - 155, - 84, - 39, - 84, - 247, - 27, - 22, - 8, - 176, - 230, - 24, - 115, - 145, - 220, - 254, - 122, - 135, - 179, - 171, - 4, - 214, - 202, - 64, - 199, - 19, - 84, - 239, - 138, - 124, - 12, -] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_schnorr/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_schnorr/src/main.nr deleted file mode 100644 index 03c635b4f6f..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_schnorr/src/main.nr +++ /dev/null @@ -1,25 +0,0 @@ -use dep::std; -// Note: If main has any unsized types, then the verifier will never be able -// to figure out the circuit instance -unconstrained fn main( - message: [u8; 10], - message_field: Field, - pub_key_x: Field, - pub_key_y: Field, - signature: [u8; 64] -) { - // Regression for issue #2421 - // We want to make sure that we can accurately verify a signature whose message is a slice vs. an array - let message_field_bytes = message_field.to_be_bytes(10); - for i in 0..10 { - assert(message[i] == message_field_bytes[i]); - } - // Is there ever a situation where someone would want - // to ensure that a signature was invalid? - // Check that passing a slice as the message is valid - let valid_signature = std::schnorr::verify_signature_slice(pub_key_x, pub_key_y, signature, message_field_bytes); - assert(valid_signature); - // Check that passing an array as the message is valid - let valid_signature = std::schnorr::verify_signature(pub_key_x, pub_key_y, signature, message); - assert(valid_signature); -} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_signed_cmp/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_signed_cmp/Nargo.toml deleted file mode 100644 index 3f485df4a82..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_signed_cmp/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "brillig_signed_cmp" -type = "bin" -authors = [""] - -[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Nargo.toml deleted file mode 100644 index df6c818c90f..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "brillig_to_be_bytes" -type = "bin" -authors = [""] - -[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Prover.toml deleted file mode 100644 index 07fe857ac7c..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Prover.toml +++ /dev/null @@ -1 +0,0 @@ -x = "2040124" diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/src/main.nr deleted file mode 100644 index 9d78411f060..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/src/main.nr +++ /dev/null @@ -1,12 +0,0 @@ -unconstrained fn main(x: Field) -> pub [u8; 31] { - // The result of this byte array will be big-endian - let byte_array = x.to_be_bytes(31); - let mut bytes = [0; 31]; - for i in 0..31 { - bytes[i] = byte_array[i]; - } - assert(bytes[30] == 60); - assert(bytes[29] == 33); - assert(bytes[28] == 31); - bytes -} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Nargo.toml deleted file mode 100644 index 991f3d1e46c..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "brillig_to_bytes_integration" -type = "bin" -authors = [""] - -[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Prover.toml deleted file mode 100644 index 23f7acea449..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = "2040124" -_y = "0x2000000000000000000000000000000000000000000000000000000000000000" diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/src/main.nr deleted file mode 100644 index e8e5b9db9ca..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/src/main.nr +++ /dev/null @@ -1,27 +0,0 @@ -use dep::std; - -unconstrained fn main(x: Field, _y: Field) { - // The result of this byte array will be big-endian - let y: Field = 2040124; - let be_byte_array = y.to_be_bytes(31); - // The result of this byte array will be little-endian - let le_byte_array = x.to_le_bytes(31); - - assert(le_byte_array[0] == 60); - assert(le_byte_array[0] == be_byte_array[30]); - assert(le_byte_array[1] == be_byte_array[29]); - assert(le_byte_array[2] == be_byte_array[28]); - - let z = 0 - 1; - let p_bytes = std::field::modulus_le_bytes(); - let z_bytes = z.to_le_bytes(32); - assert(p_bytes[10] == z_bytes[10]); - assert(p_bytes[0] == z_bytes[0] as u8 + 1 as u8); - - let p_bits = std::field::modulus_le_bits(); - let z_bits = z.to_le_bits(std::field::modulus_num_bits() as u32); - assert(z_bits[0] == 0); - assert(p_bits[100] == z_bits[100]); - - _y.to_le_bits(std::field::modulus_num_bits() as u32); -} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Nargo.toml deleted file mode 100644 index c2ce8ad01b5..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "brillig_to_le_bytes" -type = "bin" -authors = [""] - -[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Prover.toml deleted file mode 100644 index 07fe857ac7c..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Prover.toml +++ /dev/null @@ -1 +0,0 @@ -x = "2040124" diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/src/main.nr deleted file mode 100644 index 77d292cf01b..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/src/main.nr +++ /dev/null @@ -1,10 +0,0 @@ -unconstrained fn main(x: Field) -> pub [u8; 31] { - // The result of this byte array will be little-endian - let byte_array = x.to_le_bytes(31); - assert(byte_array.len() == 31); - let mut bytes = [0; 31]; - for i in 0..31 { - bytes[i] = byte_array[i]; - } - bytes -} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_top_level/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_top_level/Nargo.toml deleted file mode 100644 index f74a2a82964..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_top_level/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "brillig_top_level" -type = "bin" -authors = [""] - -[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_top_level/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_top_level/Prover.toml deleted file mode 100644 index a0150a0e562..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_top_level/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = "1" -array = ["4", "5", "6"] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/brillig_top_level/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_top_level/src/main.nr deleted file mode 100644 index 6dfd98b2c3e..00000000000 --- a/noir/noir-repo/test_programs/execution_success/brillig_top_level/src/main.nr +++ /dev/null @@ -1,6 +0,0 @@ -// Tests a very simple program. -// -// The feature being tested is brillig as the entry point. -unconstrained fn main(array: [Field; 3], x: pub Field) -> pub [Field; 2] { - [array[x], array[x + 1]] -} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_bits/Nargo.toml b/noir/noir-repo/test_programs/execution_success/empty/Nargo.toml similarity index 67% rename from noir/noir-repo/test_programs/execution_success/brillig_to_bits/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/empty/Nargo.toml index a18b769550d..168911f2b2b 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_bits/Nargo.toml +++ b/noir/noir-repo/test_programs/execution_success/empty/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "brillig_to_bits" +name = "empty" type = "bin" authors = [""] [dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/empty/src/main.nr b/noir/noir-repo/test_programs/execution_success/empty/src/main.nr new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/empty/src/main.nr @@ -0,0 +1 @@ +fn main() {} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_schnorr/Nargo.toml b/noir/noir-repo/test_programs/execution_success/signed_cmp/Nargo.toml similarity index 68% rename from noir/noir-repo/test_programs/execution_success/brillig_schnorr/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/signed_cmp/Nargo.toml index 1b598abbf74..642a0924678 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_schnorr/Nargo.toml +++ b/noir/noir-repo/test_programs/execution_success/signed_cmp/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "brillig_schnorr" +name = "signed_cmp" type = "bin" authors = [""] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_signed_cmp/Prover.toml b/noir/noir-repo/test_programs/execution_success/signed_cmp/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/execution_success/brillig_signed_cmp/Prover.toml rename to noir/noir-repo/test_programs/execution_success/signed_cmp/Prover.toml diff --git a/noir/noir-repo/test_programs/execution_success/brillig_signed_cmp/src/main.nr b/noir/noir-repo/test_programs/execution_success/signed_cmp/src/main.nr similarity index 84% rename from noir/noir-repo/test_programs/execution_success/brillig_signed_cmp/src/main.nr rename to noir/noir-repo/test_programs/execution_success/signed_cmp/src/main.nr index 3e3ea0f4b0f..85746ada8f4 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_signed_cmp/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/signed_cmp/src/main.nr @@ -1,4 +1,4 @@ -unconstrained fn main(minus_one: i8) { +fn main(minus_one: i8) { assert(minus_one < 0); assert(0 < minus_one as u8); assert(0 > minus_one); diff --git a/noir/noir-repo/test_programs/execution_success/brillig_array_eq/Nargo.toml b/noir/noir-repo/test_programs/execution_success/signed_div/Nargo.toml similarity index 67% rename from noir/noir-repo/test_programs/execution_success/brillig_array_eq/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/signed_div/Nargo.toml index 62ce392f96b..5ce137d8c0c 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_array_eq/Nargo.toml +++ b/noir/noir-repo/test_programs/execution_success/signed_div/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "brillig_array_eq" +name = "signed_div" type = "bin" authors = [""] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_signed_div/Prover.toml b/noir/noir-repo/test_programs/execution_success/signed_div/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/execution_success/brillig_signed_div/Prover.toml rename to noir/noir-repo/test_programs/execution_success/signed_div/Prover.toml diff --git a/noir/noir-repo/test_programs/execution_success/brillig_signed_div/src/main.nr b/noir/noir-repo/test_programs/execution_success/signed_div/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/execution_success/brillig_signed_div/src/main.nr rename to noir/noir-repo/test_programs/execution_success/signed_div/src/main.nr diff --git a/noir/noir-repo/test_programs/execution_success/brillig_wrapping/Nargo.toml b/noir/noir-repo/test_programs/execution_success/to_bits/Nargo.toml similarity index 66% rename from noir/noir-repo/test_programs/execution_success/brillig_wrapping/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/to_bits/Nargo.toml index a52246ba908..ef47f3b4ba1 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_wrapping/Nargo.toml +++ b/noir/noir-repo/test_programs/execution_success/to_bits/Nargo.toml @@ -1,6 +1,5 @@ [package] -name = "brillig_wrapping" +name = "to_bits" type = "bin" authors = [""] - [dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_to_bits/src/main.nr b/noir/noir-repo/test_programs/execution_success/to_bits/src/main.nr similarity index 94% rename from noir/noir-repo/test_programs/execution_success/brillig_to_bits/src/main.nr rename to noir/noir-repo/test_programs/execution_success/to_bits/src/main.nr index 7ff3d2467b5..18f65f0bd66 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_to_bits/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/to_bits/src/main.nr @@ -1,6 +1,6 @@ use dep::std; -unconstrained fn main() { +fn main() { let field = 1000; let be_bits = field.to_be_bits(16); let le_bits = field.to_le_bits(16); diff --git a/noir/noir-repo/test_programs/execution_success/unconstrained_empty/Nargo.toml b/noir/noir-repo/test_programs/execution_success/unconstrained_empty/Nargo.toml deleted file mode 100644 index 48d0f5938d8..00000000000 --- a/noir/noir-repo/test_programs/execution_success/unconstrained_empty/Nargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[package] -name = "unconstrained_empty" -type = "bin" -authors = [""] -[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/unconstrained_empty/src/main.nr b/noir/noir-repo/test_programs/execution_success/unconstrained_empty/src/main.nr deleted file mode 100644 index 5e5fb297236..00000000000 --- a/noir/noir-repo/test_programs/execution_success/unconstrained_empty/src/main.nr +++ /dev/null @@ -1 +0,0 @@ -unconstrained fn main() {} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_signed_div/Nargo.toml b/noir/noir-repo/test_programs/execution_success/wrapping_operations/Nargo.toml similarity index 65% rename from noir/noir-repo/test_programs/execution_success/brillig_signed_div/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/wrapping_operations/Nargo.toml index 4bb9c5ecc1c..3a28b3461ec 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_signed_div/Nargo.toml +++ b/noir/noir-repo/test_programs/execution_success/wrapping_operations/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "brillig_signed_div" +name = "wrapping_operations" type = "bin" authors = [""] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_wrapping/Prover.toml b/noir/noir-repo/test_programs/execution_success/wrapping_operations/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/execution_success/brillig_wrapping/Prover.toml rename to noir/noir-repo/test_programs/execution_success/wrapping_operations/Prover.toml diff --git a/noir/noir-repo/test_programs/execution_success/brillig_wrapping/src/main.nr b/noir/noir-repo/test_programs/execution_success/wrapping_operations/src/main.nr similarity index 79% rename from noir/noir-repo/test_programs/execution_success/brillig_wrapping/src/main.nr rename to noir/noir-repo/test_programs/execution_success/wrapping_operations/src/main.nr index 4153a466057..85fd65b193c 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_wrapping/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/wrapping_operations/src/main.nr @@ -1,6 +1,6 @@ use dep::std; -unconstrained fn main(x: u8, y: u8) { +fn main(x: u8, y: u8) { assert(std::wrapping_sub(x, 1) == y); assert(std::wrapping_add(y, 1) == x); assert(std::wrapping_mul(y, y) == 1); diff --git a/noir/noir-repo/tooling/debugger/ignored-tests.txt b/noir/noir-repo/tooling/debugger/ignored-tests.txt index a6d3c9a3a94..a9193896589 100644 --- a/noir/noir-repo/tooling/debugger/ignored-tests.txt +++ b/noir/noir-repo/tooling/debugger/ignored-tests.txt @@ -1,28 +1,17 @@ -array_dynamic_blackbox_input bigint -bit_shifts_comptime brillig_references brillig_to_bytes_integration debug_logs -double_verify_nested_proof -double_verify_proof -double_verify_proof_recursive -modulus -references -scalar_mul -signed_comparison -to_bytes_integration +fold_after_inlined_calls fold_basic fold_basic_nested_call fold_call_witness_condition -fold_after_inlined_calls -fold_numeric_generic_poseidon -no_predicates_basic -no_predicates_numeric_generic_poseidon -regression_4709 +fold_complex_outputs fold_distinct_return fold_fibonacci -fold_complex_outputs -slice_init_with_complex_type -hashmap -is_unconstrained \ No newline at end of file +fold_numeric_generic_poseidon +is_unconstrained +modulus +references +regression_4709 +to_bytes_integration \ No newline at end of file diff --git a/noir/noir-repo/tooling/nargo_cli/build.rs b/noir/noir-repo/tooling/nargo_cli/build.rs index 74042cf4e40..53c3966cb4c 100644 --- a/noir/noir-repo/tooling/nargo_cli/build.rs +++ b/noir/noir-repo/tooling/nargo_cli/build.rs @@ -38,6 +38,26 @@ fn main() { generate_compile_failure_tests(&mut test_file, &test_dir); } +/// Some tests are explicitly ignored in brillig due to them failing. +/// These should be fixed and removed from this list. +const IGNORED_BRILLIG_TESTS: [&str; 11] = [ + // Takes a very long time to execute as large loops do not get simplified. + &"regression_4709", + // bit sizes for bigint operation doesn't match up. + &"bigint", + // ICE due to looking for function which doesn't exist. + &"fold_after_inlined_calls", + &"fold_basic", + &"fold_basic_nested_call", + &"fold_call_witness_condition", + &"fold_complex_outputs", + &"fold_distinct_return", + &"fold_fibonacci", + &"fold_numeric_generic_poseidon", + // Expected to fail as test asserts on which runtime it is in. + &"is_unconstrained", +]; + fn generate_execution_success_tests(test_file: &mut File, test_data_dir: &Path) { let test_sub_dir = "execution_success"; let test_data_dir = test_data_dir.join(test_sub_dir); @@ -55,6 +75,9 @@ fn generate_execution_success_tests(test_file: &mut File, test_data_dir: &Path) }; let test_dir = &test_dir.path(); + let brillig_ignored = + if IGNORED_BRILLIG_TESTS.contains(&test_name.as_str()) { "\n#[ignore]" } else { "" }; + write!( test_file, r#" @@ -66,6 +89,17 @@ fn execution_success_{test_name}() {{ cmd.arg("--program-dir").arg(test_program_dir); cmd.arg("execute").arg("--force"); + cmd.assert().success(); +}} + +#[test]{brillig_ignored} +fn execution_success_{test_name}_brillig() {{ + let test_program_dir = PathBuf::from("{test_dir}"); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.arg("--program-dir").arg(test_program_dir); + cmd.arg("execute").arg("--force").arg("--force-brillig"); + cmd.assert().success(); }} "#,