From f7dc943624045aeffd7355cef299fffcf29383b4 Mon Sep 17 00:00:00 2001 From: Alex Vitkov <44268717+alexvitkov@users.noreply.github.com> Date: Tue, 5 Sep 2023 18:56:38 +0300 Subject: [PATCH 1/9] chore: remove duplicate span from FunctionReturnType (#2546) --- crates/noirc_frontend/src/ast/expression.rs | 6 +++--- crates/noirc_frontend/src/ast/function.rs | 2 +- crates/noirc_frontend/src/hir/def_collector/dc_crate.rs | 2 +- crates/noirc_frontend/src/hir/type_check/errors.rs | 5 +++-- crates/noirc_frontend/src/parser/parser.rs | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/crates/noirc_frontend/src/ast/expression.rs b/crates/noirc_frontend/src/ast/expression.rs index 6c29c89051f..1a829bd0ce7 100644 --- a/crates/noirc_frontend/src/ast/expression.rs +++ b/crates/noirc_frontend/src/ast/expression.rs @@ -377,7 +377,7 @@ pub enum FunctionReturnType { /// Returns type is not specified. Default(Span), /// Everything else. - Ty(UnresolvedType, Span), + Ty(UnresolvedType), } /// Describes the types of smart contract functions that are allowed. @@ -692,7 +692,7 @@ impl FunctionReturnType { pub fn get_type(&self) -> &UnresolvedTypeData { match self { FunctionReturnType::Default(_span) => &UnresolvedTypeData::Unit, - FunctionReturnType::Ty(typ, _span) => &typ.typ, + FunctionReturnType::Ty(typ) => &typ.typ, } } } @@ -701,7 +701,7 @@ impl Display for FunctionReturnType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { FunctionReturnType::Default(_) => f.write_str(""), - FunctionReturnType::Ty(ty, _) => write!(f, "{ty}"), + FunctionReturnType::Ty(ty) => write!(f, "{ty}"), } } } diff --git a/crates/noirc_frontend/src/ast/function.rs b/crates/noirc_frontend/src/ast/function.rs index ea6d92f0afd..9f200f87bd1 100644 --- a/crates/noirc_frontend/src/ast/function.rs +++ b/crates/noirc_frontend/src/ast/function.rs @@ -47,7 +47,7 @@ impl NoirFunction { FunctionReturnType::Default(_) => { UnresolvedType::without_span(UnresolvedTypeData::Unit) } - FunctionReturnType::Ty(ty, _) => ty.clone(), + FunctionReturnType::Ty(ty) => ty.clone(), } } pub fn name(&self) -> &str { diff --git a/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs b/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs index bc0d8d6cfc0..389e6038775 100644 --- a/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -440,7 +440,7 @@ fn resolve_trait_methods( let arguments = vecmap(parameters, |param| resolver.resolve_type(param.1.clone())); let resolved_return_type = match return_type { FunctionReturnType::Default(_) => None, - FunctionReturnType::Ty(unresolved_type, _span) => { + FunctionReturnType::Ty(unresolved_type) => { Some(resolver.resolve_type(unresolved_type.clone())) } }; diff --git a/crates/noirc_frontend/src/hir/type_check/errors.rs b/crates/noirc_frontend/src/hir/type_check/errors.rs index cd8d87435c9..3190c7a24a2 100644 --- a/crates/noirc_frontend/src/hir/type_check/errors.rs +++ b/crates/noirc_frontend/src/hir/type_check/errors.rs @@ -205,8 +205,9 @@ impl From for Diagnostic { Source::Comparison => format!("Unsupported types for comparison: {expected} and {actual}"), Source::BinOp => format!("Unsupported types for binary operation: {expected} and {actual}"), Source::Return(ret_ty, expr_span) => { - let ret_ty_span = match ret_ty { - FunctionReturnType::Default(span) | FunctionReturnType::Ty(_, span) => span + let ret_ty_span = match ret_ty.clone() { + FunctionReturnType::Default(span) => span, + FunctionReturnType::Ty(ty) => ty.span.unwrap(), }; let mut diagnostic = Diagnostic::simple_error(format!("expected type {expected}, found type {actual}"), format!("expected {expected} because of return type"), ret_ty_span); diff --git a/crates/noirc_frontend/src/parser/parser.rs b/crates/noirc_frontend/src/parser/parser.rs index 00eba5de3f3..84f1ab0da82 100644 --- a/crates/noirc_frontend/src/parser/parser.rs +++ b/crates/noirc_frontend/src/parser/parser.rs @@ -268,7 +268,7 @@ fn function_return_type() -> impl NoirParser<((Distinctness, Visibility), Functi .then(spanned(parse_type())) .or_not() .map_with_span(|ret, span| match ret { - Some((head, (ty, span))) => (head, FunctionReturnType::Ty(ty, span)), + Some((head, (ty, _))) => (head, FunctionReturnType::Ty(ty)), None => ( (Distinctness::DuplicationAllowed, Visibility::Private), FunctionReturnType::Default(span), From 255febd35a7514becfd2c39a31558ff7ab173c58 Mon Sep 17 00:00:00 2001 From: Ethan-000 <70556667+Ethan-000@users.noreply.github.com> Date: Tue, 5 Sep 2023 17:10:32 +0100 Subject: [PATCH 2/9] chore: Replace hashers of hashmaps in dfg with fxhashes (#2490) --- Cargo.lock | 1 + crates/noirc_evaluator/Cargo.toml | 1 + crates/noirc_evaluator/src/brillig/brillig_gen.rs | 13 ++++++------- .../src/brillig/brillig_gen/brillig_fn.rs | 3 +-- .../src/brillig/brillig_gen/brillig_slice_ops.rs | 4 ++-- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 2 +- crates/noirc_evaluator/src/ssa/acir_gen/mod.rs | 9 +++++---- crates/noirc_evaluator/src/ssa/ir/cfg.rs | 6 ++++-- crates/noirc_evaluator/src/ssa/ir/dfg.rs | 3 ++- crates/noirc_evaluator/src/ssa/ir/dom.rs | 5 +++-- .../noirc_evaluator/src/ssa/ir/function_inserter.rs | 5 ++--- crates/noirc_evaluator/src/ssa/ir/map.rs | 6 +++--- crates/noirc_evaluator/src/ssa/opt/array_use.rs | 5 ++--- .../noirc_evaluator/src/ssa/opt/constant_folding.rs | 5 +++-- .../noirc_evaluator/src/ssa/opt/defunctionalize.rs | 5 +++-- crates/noirc_evaluator/src/ssa/opt/flatten_cfg.rs | 7 ++++--- .../src/ssa/opt/flatten_cfg/branch_analysis.rs | 4 ++-- crates/noirc_evaluator/src/ssa/opt/inlining.rs | 9 +++++---- crates/noirc_evaluator/src/ssa/opt/unrolling.rs | 9 +++++---- crates/noirc_evaluator/src/ssa/ssa_gen/context.rs | 4 ++-- 20 files changed, 57 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5f6dd818027..b3e0a2c00d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2372,6 +2372,7 @@ name = "noirc_evaluator" version = "0.10.5" dependencies = [ "acvm", + "fxhash", "im", "iter-extended", "noirc_abi", diff --git a/crates/noirc_evaluator/Cargo.toml b/crates/noirc_evaluator/Cargo.toml index b838f936ee6..7e4265b2488 100644 --- a/crates/noirc_evaluator/Cargo.toml +++ b/crates/noirc_evaluator/Cargo.toml @@ -11,6 +11,7 @@ noirc_frontend.workspace = true noirc_errors.workspace = true noirc_abi.workspace = true acvm.workspace = true +fxhash = "0.2.1" iter-extended.workspace = true thiserror.workspace = true num-bigint = "0.4" diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen.rs b/crates/noirc_evaluator/src/brillig/brillig_gen.rs index a1e82bbf443..53e86a00e75 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen.rs @@ -4,13 +4,10 @@ pub(crate) mod brillig_directive; pub(crate) mod brillig_fn; pub(crate) mod brillig_slice_ops; -use crate::ssa::ir::{function::Function, post_order::PostOrder}; - -use std::collections::HashMap; - use self::{brillig_block::BrilligBlock, brillig_fn::FunctionContext}; - use super::brillig_ir::{artifact::BrilligArtifact, BrilligContext}; +use crate::ssa::ir::{function::Function, post_order::PostOrder}; +use fxhash::FxHashMap as HashMap; /// Converting an SSA function into Brillig bytecode. pub(crate) fn convert_ssa_function(func: &Function, enable_debug_trace: bool) -> BrilligArtifact { @@ -18,8 +15,10 @@ pub(crate) fn convert_ssa_function(func: &Function, enable_debug_trace: bool) -> reverse_post_order.extend_from_slice(PostOrder::with_function(func).as_slice()); reverse_post_order.reverse(); - let mut function_context = - FunctionContext { function_id: func.id(), ssa_value_to_brillig_variable: HashMap::new() }; + let mut function_context = FunctionContext { + function_id: func.id(), + ssa_value_to_brillig_variable: HashMap::default(), + }; let mut brillig_context = BrilligContext::new(enable_debug_trace); diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs index bfce26f4fac..1ea16fd375e 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use acvm::brillig_vm::brillig::{HeapArray, HeapVector, RegisterIndex, RegisterOrMemory}; use iter_extended::vecmap; @@ -15,6 +13,7 @@ use crate::{ value::ValueId, }, }; +use fxhash::FxHashMap as HashMap; pub(crate) struct FunctionContext { pub(crate) function_id: FunctionId, diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index facc4766722..e46cc55c3ea 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -311,7 +311,6 @@ impl<'block> BrilligBlock<'block> { #[cfg(test)] mod tests { - use std::collections::HashMap; use std::vec; use acvm::acir::brillig::{HeapVector, Value}; @@ -323,11 +322,12 @@ mod tests { use crate::brillig::brillig_ir::tests::{create_and_run_vm, create_context}; use crate::brillig::brillig_ir::BrilligContext; use crate::ssa::ir::map::Id; + use fxhash::FxHashMap as HashMap; fn create_test_environment() -> (FunctionContext, BrilligContext) { let function_context = FunctionContext { function_id: Id::test_new(0), - ssa_value_to_brillig_variable: HashMap::new(), + ssa_value_to_brillig_variable: HashMap::default(), }; let brillig_context = create_context(); (function_context, brillig_context) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index cc1888311e8..6bf9a9d1085 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -20,8 +20,8 @@ use acvm::{ FieldElement, }; use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError}; +use fxhash::FxHashMap as HashMap; use iter_extended::{try_vecmap, vecmap}; -use std::collections::HashMap; use std::{borrow::Cow, hash::Hash}; #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/mod.rs b/crates/noirc_evaluator/src/ssa/acir_gen/mod.rs index 92619c06f39..d5e1df64a6b 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -1,7 +1,7 @@ //! This file holds the pass to convert from Noir's SSA IR to ACIR. mod acir_ir; -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use std::fmt::Debug; use std::ops::RangeInclusive; @@ -29,6 +29,7 @@ use acvm::{ acir::{circuit::opcodes::BlockId, native_types::Expression}, FieldElement, }; +use fxhash::FxHashMap as HashMap; use iter_extended::{try_vecmap, vecmap}; use noirc_frontend::Distinctness; @@ -147,11 +148,11 @@ impl Context { let current_side_effects_enabled_var = acir_context.add_constant(FieldElement::one()); Context { - ssa_values: HashMap::new(), + ssa_values: HashMap::default(), current_side_effects_enabled_var, acir_context, initialized_arrays: HashSet::new(), - memory_blocks: HashMap::new(), + memory_blocks: HashMap::default(), max_block_id: 0, } } @@ -1227,7 +1228,7 @@ mod tests { let ssa = builder.finish(); let context = Context::new(); - let mut acir = context.convert_ssa(ssa, Brillig::default(), &HashMap::new()).unwrap(); + let mut acir = context.convert_ssa(ssa, Brillig::default(), &HashMap::default()).unwrap(); let expected_opcodes = vec![Opcode::Arithmetic(&Expression::one() - &Expression::from(Witness(1)))]; diff --git a/crates/noirc_evaluator/src/ssa/ir/cfg.rs b/crates/noirc_evaluator/src/ssa/ir/cfg.rs index eccb9ce587c..dbc4c29183e 100644 --- a/crates/noirc_evaluator/src/ssa/ir/cfg.rs +++ b/crates/noirc_evaluator/src/ssa/ir/cfg.rs @@ -1,9 +1,10 @@ -use std::collections::{BTreeSet, HashMap}; +use std::collections::BTreeSet; use super::{ basic_block::{BasicBlock, BasicBlockId}, function::Function, }; +use fxhash::FxHashMap as HashMap; /// A container for the successors and predecessors of some Block. #[derive(Clone, Default)] @@ -33,7 +34,8 @@ impl ControlFlowGraph { // it later comes to describe any edges after calling compute. let entry_block = func.entry_block(); let empty_node = CfgNode { predecessors: BTreeSet::new(), successors: BTreeSet::new() }; - let data = HashMap::from([(entry_block, empty_node)]); + let mut data = HashMap::default(); + data.insert(entry_block, empty_node); let mut cfg = ControlFlowGraph { data }; cfg.compute(func); diff --git a/crates/noirc_evaluator/src/ssa/ir/dfg.rs b/crates/noirc_evaluator/src/ssa/ir/dfg.rs index ea00ad3bbc1..73914c54674 100644 --- a/crates/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/crates/noirc_evaluator/src/ssa/ir/dfg.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, collections::HashMap}; +use std::borrow::Cow; use crate::ssa::ir::instruction::SimplifyResult; @@ -14,6 +14,7 @@ use super::{ }; use acvm::FieldElement; +use fxhash::FxHashMap as HashMap; use iter_extended::vecmap; use noirc_errors::Location; diff --git a/crates/noirc_evaluator/src/ssa/ir/dom.rs b/crates/noirc_evaluator/src/ssa/ir/dom.rs index df9a6c9a3a5..da55a593f9e 100644 --- a/crates/noirc_evaluator/src/ssa/ir/dom.rs +++ b/crates/noirc_evaluator/src/ssa/ir/dom.rs @@ -4,11 +4,12 @@ //! Dominator trees are useful for tasks such as identifying back-edges in loop analysis or //! calculating dominance frontiers. -use std::{cmp::Ordering, collections::HashMap}; +use std::cmp::Ordering; use super::{ basic_block::BasicBlockId, cfg::ControlFlowGraph, function::Function, post_order::PostOrder, }; +use fxhash::FxHashMap as HashMap; /// Dominator tree node. We keep one of these per reachable block. #[derive(Clone, Default)] @@ -121,7 +122,7 @@ impl DominatorTree { /// Allocate and compute a dominator tree from a pre-computed control flow graph and /// post-order counterpart. pub(crate) fn with_cfg_and_post_order(cfg: &ControlFlowGraph, post_order: &PostOrder) -> Self { - let mut dom_tree = DominatorTree { nodes: HashMap::new(), cache: HashMap::new() }; + let mut dom_tree = DominatorTree { nodes: HashMap::default(), cache: HashMap::default() }; dom_tree.compute_dominator_tree(cfg, post_order); dom_tree } diff --git a/crates/noirc_evaluator/src/ssa/ir/function_inserter.rs b/crates/noirc_evaluator/src/ssa/ir/function_inserter.rs index d9aee785016..68ece87c7c7 100644 --- a/crates/noirc_evaluator/src/ssa/ir/function_inserter.rs +++ b/crates/noirc_evaluator/src/ssa/ir/function_inserter.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use iter_extended::vecmap; use super::{ @@ -9,6 +7,7 @@ use super::{ instruction::{Instruction, InstructionId}, value::ValueId, }; +use fxhash::FxHashMap as HashMap; /// The FunctionInserter can be used to help modify existing Functions /// and map old values to new values after re-inserting optimized versions @@ -21,7 +20,7 @@ pub(crate) struct FunctionInserter<'f> { impl<'f> FunctionInserter<'f> { pub(crate) fn new(function: &'f mut Function) -> FunctionInserter<'f> { - Self { function, values: HashMap::new() } + Self { function, values: HashMap::default() } } /// Resolves a ValueId to its new, updated value. diff --git a/crates/noirc_evaluator/src/ssa/ir/map.rs b/crates/noirc_evaluator/src/ssa/ir/map.rs index bb0da6a8558..66f8ea91a3e 100644 --- a/crates/noirc_evaluator/src/ssa/ir/map.rs +++ b/crates/noirc_evaluator/src/ssa/ir/map.rs @@ -1,5 +1,5 @@ +use fxhash::FxHashMap as HashMap; use std::{ - collections::HashMap, hash::Hash, sync::atomic::{AtomicUsize, Ordering}, }; @@ -218,7 +218,7 @@ impl SparseMap { impl Default for SparseMap { fn default() -> Self { - Self { storage: HashMap::new() } + Self { storage: HashMap::default() } } } @@ -272,7 +272,7 @@ impl TwoWayMap { impl Default for TwoWayMap { fn default() -> Self { - Self { key_to_value: HashMap::new(), value_to_key: HashMap::new() } + Self { key_to_value: HashMap::default(), value_to_key: HashMap::default() } } } diff --git a/crates/noirc_evaluator/src/ssa/opt/array_use.rs b/crates/noirc_evaluator/src/ssa/opt/array_use.rs index 5b45d768e1f..cfa97cee551 100644 --- a/crates/noirc_evaluator/src/ssa/opt/array_use.rs +++ b/crates/noirc_evaluator/src/ssa/opt/array_use.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use crate::ssa::{ ir::{ basic_block::BasicBlockId, @@ -10,13 +8,14 @@ use crate::ssa::{ }, ssa_gen::Ssa, }; +use fxhash::FxHashMap as HashMap; impl Ssa { /// Map arrays with the last instruction that uses it /// For this we simply process all the instructions in execution order /// and update the map whenever there is a match pub(crate) fn find_last_array_uses(&self) -> HashMap { - let mut array_use = HashMap::new(); + let mut array_use = HashMap::default(); for func in self.functions.values() { let mut reverse_post_order = PostOrder::with_function(func).into_vec(); reverse_post_order.reverse(); diff --git a/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs b/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs index 295353989b2..06bb1716dde 100644 --- a/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -1,4 +1,4 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use iter_extended::vecmap; @@ -12,6 +12,7 @@ use crate::ssa::{ }, ssa_gen::Ssa, }; +use fxhash::FxHashMap as HashMap; impl Ssa { /// Performs constant folding on each instruction. @@ -56,7 +57,7 @@ impl Context { let instructions = function.dfg[block].take_instructions(); // Cache of instructions without any side-effects along with their outputs. - let mut cached_instruction_results: HashMap> = HashMap::new(); + let mut cached_instruction_results: HashMap> = HashMap::default(); for instruction_id in instructions { self.push_instruction(function, block, instruction_id, &mut cached_instruction_results); diff --git a/crates/noirc_evaluator/src/ssa/opt/defunctionalize.rs b/crates/noirc_evaluator/src/ssa/opt/defunctionalize.rs index 3143871e59b..a2f4aedf7da 100644 --- a/crates/noirc_evaluator/src/ssa/opt/defunctionalize.rs +++ b/crates/noirc_evaluator/src/ssa/opt/defunctionalize.rs @@ -4,7 +4,7 @@ //! with a non-literal target can be replaced with a call to an apply function. //! The apply function is a dispatch function that takes the function id as a parameter //! and dispatches to the correct target. -use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashSet}; use acvm::FieldElement; use iter_extended::vecmap; @@ -20,6 +20,7 @@ use crate::ssa::{ }, ssa_gen::Ssa, }; +use fxhash::FxHashMap as HashMap; /// Represents an 'apply' function created by this pass to dispatch higher order functions to. /// Pseudocode of an `apply` function is given below: @@ -245,7 +246,7 @@ fn create_apply_functions( ssa: &mut Ssa, variants_map: BTreeMap>, ) -> HashMap { - let mut apply_functions = HashMap::new(); + let mut apply_functions = HashMap::default(); for (signature, variants) in variants_map.into_iter() { assert!( !variants.is_empty(), diff --git a/crates/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/crates/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index 61fdc0bcd37..35f01f293b7 100644 --- a/crates/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/crates/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -131,7 +131,8 @@ //! v11 = mul v4, Field 12 //! v12 = add v10, v11 //! store v12 at v5 (new store) -use std::collections::{BTreeMap, HashMap, HashSet}; +use fxhash::FxHashMap as HashMap; +use std::collections::{BTreeMap, HashSet}; use acvm::FieldElement; use iter_extended::vecmap; @@ -218,7 +219,7 @@ fn flatten_function_cfg(function: &mut Function) { let mut context = Context { inserter: FunctionInserter::new(function), cfg, - store_values: HashMap::new(), + store_values: HashMap::default(), local_allocations: HashSet::new(), branch_ends, conditions: Vec::new(), @@ -587,7 +588,7 @@ impl<'f> Context<'f> { // args that will be merged by inline_branch_end. Since jmpifs don't have // block arguments, it is safe to use the jmpif block here. last_block: jmpif_block, - store_values: HashMap::new(), + store_values: HashMap::default(), local_allocations: HashSet::new(), } } else { diff --git a/crates/noirc_evaluator/src/ssa/opt/flatten_cfg/branch_analysis.rs b/crates/noirc_evaluator/src/ssa/opt/flatten_cfg/branch_analysis.rs index 02583a40dcd..59bee00936a 100644 --- a/crates/noirc_evaluator/src/ssa/opt/flatten_cfg/branch_analysis.rs +++ b/crates/noirc_evaluator/src/ssa/opt/flatten_cfg/branch_analysis.rs @@ -19,9 +19,9 @@ //! //! This algorithm will remember each join point found in `find_join_point_of_branches` and //! the resulting map from each split block to each join block is returned. -use std::collections::HashMap; use crate::ssa::ir::{basic_block::BasicBlockId, cfg::ControlFlowGraph, function::Function}; +use fxhash::FxHashMap as HashMap; /// Returns a `HashMap` mapping blocks that start a branch (i.e. blocks terminated with jmpif) to /// their corresponding blocks that end the branch. @@ -61,7 +61,7 @@ struct Context<'cfg> { impl<'cfg> Context<'cfg> { fn new(cfg: &'cfg ControlFlowGraph) -> Self { - Self { cfg, branch_ends: HashMap::new() } + Self { cfg, branch_ends: HashMap::default() } } fn find_join_point_of_branches( diff --git a/crates/noirc_evaluator/src/ssa/opt/inlining.rs b/crates/noirc_evaluator/src/ssa/opt/inlining.rs index 1d09fea59f8..07b524ebc96 100644 --- a/crates/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/crates/noirc_evaluator/src/ssa/opt/inlining.rs @@ -2,7 +2,7 @@ //! The purpose of this pass is to inline the instructions of each function call //! within the function caller. If all function calls are known, there will only //! be a single function remaining when the pass finishes. -use std::collections::{BTreeSet, HashMap, HashSet}; +use std::collections::{BTreeSet, HashSet}; use iter_extended::{btree_map, vecmap}; @@ -17,6 +17,7 @@ use crate::ssa::{ }, ssa_gen::Ssa, }; +use fxhash::FxHashMap as HashMap; /// An arbitrary limit to the maximum number of recursive call /// frames at any point in time. @@ -189,9 +190,9 @@ impl<'function> PerFunctionContext<'function> { Self { context, source_function, - blocks: HashMap::new(), - instructions: HashMap::new(), - values: HashMap::new(), + blocks: HashMap::default(), + instructions: HashMap::default(), + values: HashMap::default(), inlining_entry: false, } } diff --git a/crates/noirc_evaluator/src/ssa/opt/unrolling.rs b/crates/noirc_evaluator/src/ssa/opt/unrolling.rs index 4f8209ce12e..7933079b028 100644 --- a/crates/noirc_evaluator/src/ssa/opt/unrolling.rs +++ b/crates/noirc_evaluator/src/ssa/opt/unrolling.rs @@ -12,7 +12,7 @@ //! //! Note that this pass also often creates superfluous jmp instructions in the //! program that will need to be removed by a later simplify cfg pass. -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use crate::{ errors::RuntimeError, @@ -31,6 +31,7 @@ use crate::{ ssa_gen::Ssa, }, }; +use fxhash::FxHashMap as HashMap; impl Ssa { /// Unroll all loops in each SSA function. @@ -307,9 +308,9 @@ impl<'f> LoopIteration<'f> { loop_, insert_block, source_block, - blocks: HashMap::new(), - original_blocks: HashMap::new(), - visited_blocks: HashSet::new(), + blocks: HashMap::default(), + original_blocks: HashMap::default(), + visited_blocks: HashSet::default(), induction_value: None, } } diff --git a/crates/noirc_evaluator/src/ssa/ssa_gen/context.rs b/crates/noirc_evaluator/src/ssa/ssa_gen/context.rs index e5a982912ee..5631aa8d351 100644 --- a/crates/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/crates/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::rc::Rc; use std::sync::{Mutex, RwLock}; @@ -19,6 +18,7 @@ use crate::ssa::ir::types::{NumericType, Type}; use crate::ssa::ir::value::ValueId; use super::value::{Tree, Value, Values}; +use fxhash::FxHashMap as HashMap; /// The FunctionContext is the main context object for translating a /// function into SSA form during the SSA-gen pass. @@ -94,7 +94,7 @@ impl<'a> FunctionContext<'a> { .1; let builder = FunctionBuilder::new(function_name, function_id, runtime); - let mut this = Self { definitions: HashMap::new(), builder, shared_context }; + let mut this = Self { definitions: HashMap::default(), builder, shared_context }; this.add_parameters_to_scope(parameters); this } From 8af53bf0cbae1e2b38ba29c43bdeabed46ac66e5 Mon Sep 17 00:00:00 2001 From: jfecher Date: Tue, 5 Sep 2023 12:01:58 -0500 Subject: [PATCH 3/9] chore: Cleanup mem2reg pass (#2531) --- crates/noirc_evaluator/src/ssa/opt/mem2reg.rs | 264 ++---------------- .../src/ssa/opt/mem2reg/alias_set.rs | 76 +++++ .../src/ssa/opt/mem2reg/block.rs | 243 ++++++++++++++++ 3 files changed, 350 insertions(+), 233 deletions(-) create mode 100644 crates/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs create mode 100644 crates/noirc_evaluator/src/ssa/opt/mem2reg/block.rs diff --git a/crates/noirc_evaluator/src/ssa/opt/mem2reg.rs b/crates/noirc_evaluator/src/ssa/opt/mem2reg.rs index 8c74a500bca..71524ab9736 100644 --- a/crates/noirc_evaluator/src/ssa/opt/mem2reg.rs +++ b/crates/noirc_evaluator/src/ssa/opt/mem2reg.rs @@ -61,6 +61,9 @@ //! SSA optimization pipeline, although it will be more successful the simpler the program's CFG is. //! This pass is currently performed several times to enable other passes - most notably being //! performed before loop unrolling to try to allow for mutable variables used for loop indices. +mod alias_set; +mod block; + use std::collections::{BTreeMap, BTreeSet}; use crate::ssa::{ @@ -78,6 +81,9 @@ use crate::ssa::{ ssa_gen::Ssa, }; +use self::alias_set::AliasSet; +use self::block::{Block, Expression}; + impl Ssa { /// Attempts to remove any load instructions that recover values that are already available in /// scope, and attempts to remove stores that are subsequently redundant. @@ -107,45 +113,6 @@ struct PerFunctionContext<'f> { instructions_to_remove: BTreeSet, } -#[derive(Debug, Default, Clone)] -struct Block { - /// Maps a ValueId to the Expression it represents. - /// Multiple ValueIds can map to the same Expression, e.g. - /// dereferences to the same allocation. - expressions: BTreeMap, - - /// Each expression is tracked as to how many aliases it - /// may have. If there is only 1, we can attempt to optimize - /// out any known loads to that alias. Note that "alias" here - /// includes the original reference as well. - aliases: BTreeMap>, - - /// Each allocate instruction result (and some reference block parameters) - /// will map to a Reference value which tracks whether the last value stored - /// to the reference is known. - references: BTreeMap, - - /// The last instance of a `Store` instruction to each address in this block - last_stores: BTreeMap, -} - -/// An `Expression` here is used to represent a canonical key -/// into the aliases map since otherwise two dereferences of the -/// same address will be given different ValueIds. -#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] -enum Expression { - Dereference(Box), - ArrayElement(Box), - Other(ValueId), -} - -/// Every reference's value is either Known and can be optimized away, or Unknown. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -enum ReferenceValue { - Unknown, - Known(ValueId), -} - impl<'f> PerFunctionContext<'f> { fn new(function: &'f mut Function) -> Self { let cfg = ControlFlowGraph::with_function(function); @@ -234,9 +201,10 @@ impl<'f> PerFunctionContext<'f> { if let Some(expression) = references.expressions.get(allocation) { if let Some(aliases) = references.aliases.get(expression) { let allocation_aliases_parameter = - aliases.iter().any(|alias| reference_parameters.contains(alias)); + aliases.any(|alias| reference_parameters.contains(&alias)); - if !aliases.is_empty() && !allocation_aliases_parameter { + // If `allocation_aliases_parameter` is known to be false + if allocation_aliases_parameter == Some(false) { self.instructions_to_remove.insert(*instruction); } } @@ -290,17 +258,11 @@ impl<'f> PerFunctionContext<'f> { references.set_known_value(address, value); references.last_stores.insert(address, instruction); } - Instruction::Call { arguments, .. } => { - self.mark_all_unknown(arguments, references); - } Instruction::Allocate => { // Register the new reference let result = self.inserter.function.dfg.instruction_results(instruction)[0]; references.expressions.insert(result, Expression::Other(result)); - - let mut aliases = BTreeSet::new(); - aliases.insert(result); - references.aliases.insert(Expression::Other(result), aliases); + references.aliases.insert(Expression::Other(result), AliasSet::known(result)); } Instruction::ArrayGet { array, .. } => { let result = self.inserter.function.dfg.instruction_results(instruction)[0]; @@ -317,28 +279,34 @@ impl<'f> PerFunctionContext<'f> { } Instruction::ArraySet { array, value, .. } => { references.mark_value_used(*array, self.inserter.function); + let element_type = self.inserter.function.dfg.type_of_value(*value); - if self.inserter.function.dfg.value_is_reference(*value) { + if Self::contains_references(&element_type) { let result = self.inserter.function.dfg.instruction_results(instruction)[0]; let array = self.inserter.function.dfg.resolve(*array); let expression = Expression::ArrayElement(Box::new(Expression::Other(array))); - if let Some(aliases) = references.aliases.get_mut(&expression) { - aliases.insert(result); + let mut aliases = if let Some(aliases) = references.aliases.get_mut(&expression) + { + aliases.clone() } else if let Some((elements, _)) = self.inserter.function.dfg.get_array_constant(array) { - // TODO: This should be a unification of each alias set - // If any are empty, the whole should be as well. - for reference in elements { - self.try_add_alias(references, reference, array); - } - } + let aliases = references.collect_all_aliases(elements); + self.set_aliases(references, array, aliases.clone()); + aliases + } else { + AliasSet::unknown() + }; + + aliases.unify(&references.get_aliases_for_value(*value)); - references.expressions.insert(result, expression); + references.expressions.insert(result, expression.clone()); + references.aliases.insert(expression, aliases); } } + Instruction::Call { arguments, .. } => self.mark_all_unknown(arguments, references), _ => (), } } @@ -369,12 +337,11 @@ impl<'f> PerFunctionContext<'f> { } } - fn try_add_alias(&self, references: &mut Block, reference: ValueId, alias: ValueId) { - if let Some(expression) = references.expressions.get(&reference) { - if let Some(aliases) = references.aliases.get_mut(expression) { - aliases.insert(alias); - } - } + fn set_aliases(&self, references: &mut Block, address: ValueId, new_aliases: AliasSet) { + let expression = + references.expressions.entry(address).or_insert(Expression::Other(address)); + let aliases = references.aliases.entry(expression.clone()).or_default(); + *aliases = new_aliases; } fn mark_all_unknown(&self, values: &[ValueId], references: &mut Block) { @@ -432,175 +399,6 @@ impl<'f> PerFunctionContext<'f> { } } -impl Block { - /// If the given reference id points to a known value, return the value - fn get_known_value(&self, address: ValueId) -> Option { - if let Some(expression) = self.expressions.get(&address) { - if let Some(aliases) = self.aliases.get(expression) { - // We could allow multiple aliases if we check that the reference - // value in each is equal. - if aliases.len() == 1 { - let alias = aliases.first().expect("There should be exactly 1 alias"); - - if let Some(ReferenceValue::Known(value)) = self.references.get(alias) { - return Some(*value); - } - } - } - } - None - } - - /// If the given address is known, set its value to `ReferenceValue::Known(value)`. - fn set_known_value(&mut self, address: ValueId, value: ValueId) { - self.set_value(address, ReferenceValue::Known(value)); - } - - fn set_unknown(&mut self, address: ValueId) { - self.set_value(address, ReferenceValue::Unknown); - } - - fn set_value(&mut self, address: ValueId, value: ReferenceValue) { - let expression = self.expressions.entry(address).or_insert(Expression::Other(address)); - let aliases = self.aliases.entry(expression.clone()).or_default(); - - if aliases.is_empty() { - // uh-oh, we don't know at all what this reference refers to, could be anything. - // Now we have to invalidate every reference we know of - self.invalidate_all_references(); - } else if aliases.len() == 1 { - let alias = aliases.first().expect("There should be exactly 1 alias"); - self.references.insert(*alias, value); - } else { - // More than one alias. We're not sure which it refers to so we have to - // conservatively invalidate all references it may refer to. - for alias in aliases.iter() { - if let Some(reference_value) = self.references.get_mut(alias) { - *reference_value = ReferenceValue::Unknown; - } - } - } - } - - fn invalidate_all_references(&mut self) { - for reference_value in self.references.values_mut() { - *reference_value = ReferenceValue::Unknown; - } - - self.last_stores.clear(); - } - - fn unify(mut self, other: &Self) -> Self { - for (value_id, expression) in &other.expressions { - if let Some(existing) = self.expressions.get(value_id) { - assert_eq!(existing, expression, "Expected expressions for {value_id} to be equal"); - } else { - self.expressions.insert(*value_id, expression.clone()); - } - } - - for (expression, new_aliases) in &other.aliases { - let expression = expression.clone(); - - self.aliases - .entry(expression) - .and_modify(|aliases| { - for alias in new_aliases { - aliases.insert(*alias); - } - }) - .or_insert_with(|| new_aliases.clone()); - } - - // Keep only the references present in both maps. - let mut intersection = BTreeMap::new(); - for (value_id, reference) in &other.references { - if let Some(existing) = self.references.get(value_id) { - intersection.insert(*value_id, existing.unify(*reference)); - } - } - self.references = intersection; - - self - } - - /// Remember that `result` is the result of dereferencing `address`. This is important to - /// track aliasing when references are stored within other references. - fn remember_dereference(&mut self, function: &Function, address: ValueId, result: ValueId) { - if function.dfg.value_is_reference(result) { - if let Some(known_address) = self.get_known_value(address) { - self.expressions.insert(result, Expression::Other(known_address)); - } else { - let expression = Expression::Dereference(Box::new(Expression::Other(address))); - self.expressions.insert(result, expression); - // No known aliases to insert for this expression... can we find an alias - // even if we don't have a known address? If not we'll have to invalidate all - // known references if this reference is ever stored to. - } - } - } - - /// Iterate through each known alias of the given address and apply the function `f` to each. - fn for_each_alias_of( - &mut self, - address: ValueId, - mut f: impl FnMut(&mut Self, ValueId) -> T, - ) { - if let Some(expr) = self.expressions.get(&address) { - if let Some(aliases) = self.aliases.get(expr).cloned() { - for alias in aliases { - f(self, alias); - } - } - } - } - - fn keep_last_stores_for(&mut self, address: ValueId, function: &Function) { - let address = function.dfg.resolve(address); - self.keep_last_store(address, function); - self.for_each_alias_of(address, |t, alias| t.keep_last_store(alias, function)); - } - - fn keep_last_store(&mut self, address: ValueId, function: &Function) { - let address = function.dfg.resolve(address); - - if let Some(instruction) = self.last_stores.remove(&address) { - // Whenever we decide we want to keep a store instruction, we also need - // to go through its stored value and mark that used as well. - match &function.dfg[instruction] { - Instruction::Store { value, .. } => { - self.mark_value_used(*value, function); - } - other => { - unreachable!("last_store held an id of a non-store instruction: {other:?}") - } - } - } - } - - fn mark_value_used(&mut self, value: ValueId, function: &Function) { - self.keep_last_stores_for(value, function); - - // We must do a recursive check for arrays since they're the only Values which may contain - // other ValueIds. - if let Some((array, _)) = function.dfg.get_array_constant(value) { - for value in array { - self.mark_value_used(value, function); - } - } - } -} - -impl ReferenceValue { - fn unify(self, other: Self) -> Self { - if self == other { - self - } else { - ReferenceValue::Unknown - } - } -} - #[cfg(test)] mod tests { use std::rc::Rc; diff --git a/crates/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs b/crates/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs new file mode 100644 index 00000000000..5477025e429 --- /dev/null +++ b/crates/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs @@ -0,0 +1,76 @@ +use std::collections::BTreeSet; + +use crate::ssa::ir::value::ValueId; + +/// A set of possible aliases. Each ValueId in this set represents one possible value the reference +/// holding this AliasSet may be aliased to. This struct wrapper is provided so that when we take +/// the union of multiple alias sets, the result should be empty if any individual set is empty. +/// +/// Note that we distinguish between "definitely has no aliases" - `Some(BTreeSet::new())`, and +/// "unknown which aliases this may refer to" - `None`. +#[derive(Debug, Default, Clone)] +pub(super) struct AliasSet { + aliases: Option>, +} + +impl AliasSet { + pub(super) fn unknown() -> AliasSet { + Self { aliases: None } + } + + pub(super) fn known(value: ValueId) -> AliasSet { + let mut aliases = BTreeSet::new(); + aliases.insert(value); + Self { aliases: Some(aliases) } + } + + /// In rare cases, such as when creating an empty array of references, the set of aliases for a + /// particular value will be known to be zero, which is distinct from being unknown and + /// possibly referring to any alias. + pub(super) fn known_empty() -> AliasSet { + Self { aliases: Some(BTreeSet::new()) } + } + + pub(super) fn is_unknown(&self) -> bool { + self.aliases.is_none() + } + + /// Return the single known alias if there is exactly one. + /// Otherwise, return None. + pub(super) fn single_alias(&self) -> Option { + self.aliases + .as_ref() + .and_then(|aliases| (aliases.len() == 1).then(|| *aliases.first().unwrap())) + } + + /// Unify this alias set with another. The result of this set is empty if either set is empty. + /// Otherwise, it is the union of both alias sets. + pub(super) fn unify(&mut self, other: &Self) { + if let (Some(self_aliases), Some(other_aliases)) = (&mut self.aliases, &other.aliases) { + self_aliases.extend(other_aliases); + } else { + self.aliases = None; + } + } + + /// Inserts a new alias into this set if it is not unknown + pub(super) fn insert(&mut self, new_alias: ValueId) { + if let Some(aliases) = &mut self.aliases { + aliases.insert(new_alias); + } + } + + /// Returns `Some(true)` if `f` returns true for any known alias in this set. + /// If this alias set is unknown, None is returned. + pub(super) fn any(&self, f: impl FnMut(ValueId) -> bool) -> Option { + self.aliases.as_ref().map(|aliases| aliases.iter().copied().any(f)) + } + + pub(super) fn for_each(&self, mut f: impl FnMut(ValueId)) { + if let Some(aliases) = &self.aliases { + for alias in aliases { + f(*alias); + } + } + } +} diff --git a/crates/noirc_evaluator/src/ssa/opt/mem2reg/block.rs b/crates/noirc_evaluator/src/ssa/opt/mem2reg/block.rs new file mode 100644 index 00000000000..22c5705b723 --- /dev/null +++ b/crates/noirc_evaluator/src/ssa/opt/mem2reg/block.rs @@ -0,0 +1,243 @@ +use std::{borrow::Cow, collections::BTreeMap}; + +use crate::ssa::ir::{ + function::Function, + instruction::{Instruction, InstructionId}, + value::ValueId, +}; + +use super::alias_set::AliasSet; + +/// A `Block` acts as a per-block context for the mem2reg pass. +/// Most notably, it contains the current alias set thought to track each +/// reference value if known, and it contains the expected ReferenceValue +/// for each ValueId. When a block is finished, the final values of these +/// are expected to match the values held by each ValueId at the very end +/// of a block. +#[derive(Debug, Default, Clone)] +pub(super) struct Block { + /// Maps a ValueId to the Expression it represents. + /// Multiple ValueIds can map to the same Expression, e.g. + /// dereferences to the same allocation. + pub(super) expressions: BTreeMap, + + /// Each expression is tracked as to how many aliases it + /// may have. If there is only 1, we can attempt to optimize + /// out any known loads to that alias. Note that "alias" here + /// includes the original reference as well. + pub(super) aliases: BTreeMap, + + /// Each allocate instruction result (and some reference block parameters) + /// will map to a Reference value which tracks whether the last value stored + /// to the reference is known. + pub(super) references: BTreeMap, + + /// The last instance of a `Store` instruction to each address in this block + pub(super) last_stores: BTreeMap, +} + +/// An `Expression` here is used to represent a canonical key +/// into the aliases map since otherwise two dereferences of the +/// same address will be given different ValueIds. +#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] +pub(super) enum Expression { + Dereference(Box), + ArrayElement(Box), + Other(ValueId), +} + +/// Every reference's value is either Known and can be optimized away, or Unknown. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub(super) enum ReferenceValue { + Unknown, + Known(ValueId), +} + +impl ReferenceValue { + fn unify(self, other: Self) -> Self { + if self == other { + self + } else { + ReferenceValue::Unknown + } + } +} + +impl Block { + /// If the given reference id points to a known value, return the value + pub(super) fn get_known_value(&self, address: ValueId) -> Option { + if let Some(expression) = self.expressions.get(&address) { + if let Some(aliases) = self.aliases.get(expression) { + // We could allow multiple aliases if we check that the reference + // value in each is equal. + if let Some(alias) = aliases.single_alias() { + if let Some(ReferenceValue::Known(value)) = self.references.get(&alias) { + return Some(*value); + } + } + } + } + None + } + + /// If the given address is known, set its value to `ReferenceValue::Known(value)`. + pub(super) fn set_known_value(&mut self, address: ValueId, value: ValueId) { + self.set_value(address, ReferenceValue::Known(value)); + } + + pub(super) fn set_unknown(&mut self, address: ValueId) { + self.set_value(address, ReferenceValue::Unknown); + } + + fn set_value(&mut self, address: ValueId, value: ReferenceValue) { + let expression = self.expressions.entry(address).or_insert(Expression::Other(address)); + let aliases = self.aliases.entry(expression.clone()).or_default(); + + if aliases.is_unknown() { + // uh-oh, we don't know at all what this reference refers to, could be anything. + // Now we have to invalidate every reference we know of + self.invalidate_all_references(); + } else if let Some(alias) = aliases.single_alias() { + self.references.insert(alias, value); + } else { + // More than one alias. We're not sure which it refers to so we have to + // conservatively invalidate all references it may refer to. + aliases.for_each(|alias| { + if let Some(reference_value) = self.references.get_mut(&alias) { + *reference_value = ReferenceValue::Unknown; + } + }); + } + } + + fn invalidate_all_references(&mut self) { + for reference_value in self.references.values_mut() { + *reference_value = ReferenceValue::Unknown; + } + + self.last_stores.clear(); + } + + pub(super) fn unify(mut self, other: &Self) -> Self { + for (value_id, expression) in &other.expressions { + if let Some(existing) = self.expressions.get(value_id) { + assert_eq!(existing, expression, "Expected expressions for {value_id} to be equal"); + } else { + self.expressions.insert(*value_id, expression.clone()); + } + } + + for (expression, new_aliases) in &other.aliases { + let expression = expression.clone(); + + self.aliases + .entry(expression) + .and_modify(|aliases| aliases.unify(new_aliases)) + .or_insert_with(|| new_aliases.clone()); + } + + // Keep only the references present in both maps. + let mut intersection = BTreeMap::new(); + for (value_id, reference) in &other.references { + if let Some(existing) = self.references.get(value_id) { + intersection.insert(*value_id, existing.unify(*reference)); + } + } + self.references = intersection; + + self + } + + /// Remember that `result` is the result of dereferencing `address`. This is important to + /// track aliasing when references are stored within other references. + pub(super) fn remember_dereference( + &mut self, + function: &Function, + address: ValueId, + result: ValueId, + ) { + if function.dfg.value_is_reference(result) { + if let Some(known_address) = self.get_known_value(address) { + self.expressions.insert(result, Expression::Other(known_address)); + } else { + let expression = Expression::Dereference(Box::new(Expression::Other(address))); + self.expressions.insert(result, expression); + // No known aliases to insert for this expression... can we find an alias + // even if we don't have a known address? If not we'll have to invalidate all + // known references if this reference is ever stored to. + } + } + } + + /// Iterate through each known alias of the given address and apply the function `f` to each. + fn for_each_alias_of( + &mut self, + address: ValueId, + mut f: impl FnMut(&mut Self, ValueId) -> T, + ) { + if let Some(expr) = self.expressions.get(&address) { + if let Some(aliases) = self.aliases.get(expr).cloned() { + aliases.for_each(|alias| { + f(self, alias); + }); + } + } + } + + fn keep_last_stores_for(&mut self, address: ValueId, function: &Function) { + let address = function.dfg.resolve(address); + self.keep_last_store(address, function); + self.for_each_alias_of(address, |t, alias| t.keep_last_store(alias, function)); + } + + fn keep_last_store(&mut self, address: ValueId, function: &Function) { + let address = function.dfg.resolve(address); + + if let Some(instruction) = self.last_stores.remove(&address) { + // Whenever we decide we want to keep a store instruction, we also need + // to go through its stored value and mark that used as well. + match &function.dfg[instruction] { + Instruction::Store { value, .. } => { + self.mark_value_used(*value, function); + } + other => { + unreachable!("last_store held an id of a non-store instruction: {other:?}") + } + } + } + } + + pub(super) fn mark_value_used(&mut self, value: ValueId, function: &Function) { + self.keep_last_stores_for(value, function); + + // We must do a recursive check for arrays since they're the only Values which may contain + // other ValueIds. + if let Some((array, _)) = function.dfg.get_array_constant(value) { + for value in array { + self.mark_value_used(value, function); + } + } + } + + /// Collect all aliases used by the given value list + pub(super) fn collect_all_aliases( + &self, + values: impl IntoIterator, + ) -> AliasSet { + let mut aliases = AliasSet::known_empty(); + for value in values { + aliases.unify(&self.get_aliases_for_value(value)); + } + aliases + } + + pub(super) fn get_aliases_for_value(&self, value: ValueId) -> Cow { + if let Some(expression) = self.expressions.get(&value) { + if let Some(aliases) = self.aliases.get(expression) { + return Cow::Borrowed(aliases); + } + } + + Cow::Owned(AliasSet::unknown()) + } +} From ed229ddd303f86e4d2c9227670e729cfa67e72c0 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 5 Sep 2023 18:14:02 +0100 Subject: [PATCH 4/9] chore: refactor `constant_folding` pass (#2533) --- .../src/ssa/opt/constant_folding.rs | 173 ++++++++++++++---- 1 file changed, 133 insertions(+), 40 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs b/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs index 06bb1716dde..51592a13ae5 100644 --- a/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -1,3 +1,23 @@ +//! The goal of the constant folding optimization pass is to propagate any constants forwards into +//! later [`Instruction`]s to maximize the impact of [compile-time simplifications][Instruction::simplify()]. +//! +//! The pass works as follows: +//! - Re-insert each instruction in order to apply the instruction simplification performed +//! by the [`DataFlowGraph`] automatically as new instructions are pushed. +//! - Check whether the instruction is [pure][Instruction::is_pure()] +//! and there exists a duplicate instruction earlier in the same block. +//! If so, the instruction can be replaced with the results of this previous instruction. +//! +//! These operations are done in parallel so that they can each benefit from each other +//! without the need for multiple passes. +//! +//! Other passes perform a certain amount of constant folding automatically as they insert instructions +//! into the [`DataFlowGraph`] but this pass can become needed if [`DataFlowGraph::set_value`] or +//! [`DataFlowGraph::set_value_from_id`] are used on a value which enables instructions dependent on the value to +//! now be simplified. +//! +//! This is the only pass which removes duplicated pure [`Instruction`]s however and so is needed when +//! different blocks are merged, i.e. after the [`flatten_cfg`][super::flatten_cfg] pass. use std::collections::HashSet; use iter_extended::vecmap; @@ -5,7 +25,7 @@ use iter_extended::vecmap; use crate::ssa::{ ir::{ basic_block::BasicBlockId, - dfg::InsertInstructionResult, + dfg::{DataFlowGraph, InsertInstructionResult}, function::Function, instruction::{Instruction, InstructionId}, value::ValueId, @@ -17,10 +37,7 @@ use fxhash::FxHashMap as HashMap; impl Ssa { /// Performs constant folding on each instruction. /// - /// This is generally done automatically but this pass can become needed - /// if `DataFlowGraph::set_value` or `DataFlowGraph::set_value_from_id` are - /// used on a value which enables instructions dependent on the value to - /// now be simplified. + /// See [`constant_folding`][self] module for more information. pub(crate) fn fold_constants(mut self) -> Ssa { for function in self.functions.values_mut() { constant_fold(function); @@ -60,57 +77,88 @@ impl Context { let mut cached_instruction_results: HashMap> = HashMap::default(); for instruction_id in instructions { - self.push_instruction(function, block, instruction_id, &mut cached_instruction_results); + Self::fold_constants_into_instruction( + &mut function.dfg, + block, + instruction_id, + &mut cached_instruction_results, + ); } self.block_queue.extend(function.dfg[block].successors()); } - fn push_instruction( - &mut self, - function: &mut Function, + fn fold_constants_into_instruction( + dfg: &mut DataFlowGraph, block: BasicBlockId, id: InstructionId, instruction_result_cache: &mut HashMap>, ) { - let instruction = function.dfg[id].clone(); - let old_results = function.dfg.instruction_results(id).to_vec(); - - // Resolve any inputs to ensure that we're comparing like-for-like instructions. - let instruction = instruction.map_values(|value_id| function.dfg.resolve(value_id)); + let instruction = Self::resolve_instruction(id, dfg); + let old_results = dfg.instruction_results(id).to_vec(); - // If a copy of this instruction exists earlier in the block then reuse the previous results. + // If a copy of this instruction exists earlier in the block, then reuse the previous results. if let Some(cached_results) = instruction_result_cache.get(&instruction) { - for (old_result, new_result) in old_results.iter().zip(cached_results) { - function.dfg.set_value_from_id(*old_result, *new_result); - } + Self::replace_result_ids(dfg, &old_results, cached_results); return; } - let ctrl_typevars = instruction - .requires_ctrl_typevars() - .then(|| vecmap(&old_results, |result| function.dfg.type_of_value(*result))); - - let call_stack = function.dfg.get_call_stack(id); - let new_results = match function.dfg.insert_instruction_and_results( - instruction.clone(), - block, - ctrl_typevars, - call_stack, - ) { - InsertInstructionResult::SimplifiedTo(new_result) => vec![new_result], - InsertInstructionResult::SimplifiedToMultiple(new_results) => new_results, - InsertInstructionResult::Results(_, new_results) => new_results.to_vec(), - InsertInstructionResult::InstructionRemoved => vec![], - }; - assert_eq!(old_results.len(), new_results.len()); + // Otherwise, try inserting the instruction again to apply any optimizations using the newly resolved inputs. + let new_results = Self::push_instruction(id, instruction.clone(), &old_results, block, dfg); - // If the instruction doesn't have side-effects, cache the results so we can reuse them if + // If the instruction is pure then we cache the results so we can reuse them if // the same instruction appears again later in the block. - if instruction.is_pure(&function.dfg) { + if instruction.is_pure(dfg) { instruction_result_cache.insert(instruction, new_results.clone()); } + Self::replace_result_ids(dfg, &old_results, &new_results); + } + + /// Fetches an [`Instruction`] by its [`InstructionId`] and fully resolves its inputs. + fn resolve_instruction(instruction_id: InstructionId, dfg: &DataFlowGraph) -> Instruction { + let instruction = dfg[instruction_id].clone(); + + // Resolve any inputs to ensure that we're comparing like-for-like instructions. + instruction.map_values(|value_id| dfg.resolve(value_id)) + } + + /// Pushes a new [`Instruction`] into the [`DataFlowGraph`] which applies any optimizations + /// based on newly resolved values for its inputs. + /// + /// This may result in the [`Instruction`] being optimized away or replaced with a constant value. + fn push_instruction( + id: InstructionId, + instruction: Instruction, + old_results: &[ValueId], + block: BasicBlockId, + dfg: &mut DataFlowGraph, + ) -> Vec { + let ctrl_typevars = instruction + .requires_ctrl_typevars() + .then(|| vecmap(old_results, |result| dfg.type_of_value(*result))); + + let call_stack = dfg.get_call_stack(id); + let new_results = + match dfg.insert_instruction_and_results(instruction, block, ctrl_typevars, call_stack) + { + InsertInstructionResult::SimplifiedTo(new_result) => vec![new_result], + InsertInstructionResult::SimplifiedToMultiple(new_results) => new_results, + InsertInstructionResult::Results(_, new_results) => new_results.to_vec(), + InsertInstructionResult::InstructionRemoved => vec![], + }; + // Optimizations while inserting the instruction should not change the number of results. + assert_eq!(old_results.len(), new_results.len()); + + new_results + } + + /// Replaces a set of [`ValueId`]s inside the [`DataFlowGraph`] with another. + fn replace_result_ids( + dfg: &mut DataFlowGraph, + old_results: &[ValueId], + new_results: &[ValueId], + ) { for (old_result, new_result) in old_results.iter().zip(new_results) { - function.dfg.set_value_from_id(*old_result, new_result); + dfg.set_value_from_id(*old_result, *new_result); } } } @@ -123,10 +171,10 @@ mod test { function_builder::FunctionBuilder, ir::{ function::RuntimeType, - instruction::{BinaryOp, TerminatorInstruction}, + instruction::{BinaryOp, Instruction, TerminatorInstruction}, map::Id, types::Type, - value::Value, + value::{Value, ValueId}, }, }; @@ -228,4 +276,49 @@ mod test { // The return element is expected to refer to the new add instruction result. assert_eq!(main.dfg.resolve(new_add_instr_result), main.dfg.resolve(return_element)); } + + #[test] + fn instruction_deduplication() { + // fn main f0 { + // b0(v0: Field): + // v1 = cast v0 as u32 + // v2 = cast v0 as u32 + // constrain v1 v2 + // } + // + // After constructing this IR, we run constant folding which should replace the second cast + // with a reference to the results to the first. This then allows us to optimize away + // the constrain instruction as both inputs are known to be equal. + // + // The first cast instruction is retained and will be removed in the dead instruction elimination pass. + let main_id = Id::test_new(0); + + // Compiling main + let mut builder = FunctionBuilder::new("main".into(), main_id, RuntimeType::Acir); + let v0 = builder.add_parameter(Type::field()); + + let v1 = builder.insert_cast(v0, Type::unsigned(32)); + let v2 = builder.insert_cast(v0, Type::unsigned(32)); + builder.insert_constrain(v1, v2, None); + + let mut ssa = builder.finish(); + let main = ssa.main_mut(); + let instructions = main.dfg[main.entry_block()].instructions(); + assert_eq!(instructions.len(), 3); + + // Expected output: + // + // fn main f0 { + // b0(v0: Field): + // v1 = cast v0 as u32 + // } + let ssa = ssa.fold_constants(); + let main = ssa.main(); + let instructions = main.dfg[main.entry_block()].instructions(); + + assert_eq!(instructions.len(), 1); + let instruction = &main.dfg[instructions[0]]; + + assert_eq!(instruction, &Instruction::Cast(ValueId::test_new(0), Type::unsigned(32))); + } } From d49e0affa00fd29e7e5033ef464dbdd217980c8e Mon Sep 17 00:00:00 2001 From: jfecher Date: Tue, 5 Sep 2023 12:21:41 -0500 Subject: [PATCH 5/9] fix: Make def collector ordering more deterministic (#2515) --- .../type_aliases/src/main.nr | 4 +- crates/noirc_frontend/src/ast/mod.rs | 10 ++--- crates/noirc_frontend/src/graph/mod.rs | 2 +- .../src/hir/def_collector/dc_crate.rs | 30 +++++++------- crates/noirc_frontend/src/hir/def_map/mod.rs | 12 +++--- crates/noirc_frontend/src/hir/mod.rs | 10 ++--- .../src/hir/resolution/import.rs | 14 +++---- .../src/hir/resolution/path_resolver.rs | 8 ++-- .../src/hir/resolution/resolver.rs | 39 ++++++++++++------- .../noirc_frontend/src/hir/type_check/mod.rs | 8 ++-- .../src/monomorphization/mod.rs | 8 ++-- crates/noirc_frontend/src/node_interner.rs | 6 +-- 12 files changed, 84 insertions(+), 67 deletions(-) diff --git a/crates/nargo_cli/tests/execution_success/type_aliases/src/main.nr b/crates/nargo_cli/tests/execution_success/type_aliases/src/main.nr index 7197c23f664..573a501367f 100644 --- a/crates/nargo_cli/tests/execution_success/type_aliases/src/main.nr +++ b/crates/nargo_cli/tests/execution_success/type_aliases/src/main.nr @@ -2,9 +2,9 @@ type Foo = [T; 2]; type Bar = Field; -type Three = Two; -type Two = One; type One = (A, B); +type Two = One; +type Three = Two; struct MyStruct { foo: Bar, diff --git a/crates/noirc_frontend/src/ast/mod.rs b/crates/noirc_frontend/src/ast/mod.rs index e92d333fd69..aa79929fdd7 100644 --- a/crates/noirc_frontend/src/ast/mod.rs +++ b/crates/noirc_frontend/src/ast/mod.rs @@ -124,17 +124,17 @@ impl std::fmt::Display for UnresolvedTypeData { }, FormatString(len, elements) => write!(f, "fmt<{len}, {elements}"), Function(args, ret, env) => { - let args = vecmap(args, ToString::to_string); + let args = vecmap(args, ToString::to_string).join(", "); match &env.as_ref().typ { UnresolvedTypeData::Unit => { - write!(f, "fn({}) -> {ret}", args.join(", ")) + write!(f, "fn({args}) -> {ret}") } UnresolvedTypeData::Tuple(env_types) => { - let env_types = vecmap(env_types, |arg| ToString::to_string(&arg.typ)); - write!(f, "fn[{}]({}) -> {ret}", env_types.join(", "), args.join(", ")) + let env_types = vecmap(env_types, |arg| arg.typ.to_string()).join(", "); + write!(f, "fn[{env_types}]({args}) -> {ret}") } - _ => unreachable!(), + other => write!(f, "fn[{other}]({args}) -> {ret}"), } } MutableReference(element) => write!(f, "&mut {element}"), diff --git a/crates/noirc_frontend/src/graph/mod.rs b/crates/noirc_frontend/src/graph/mod.rs index af79219d5de..d8c539038df 100644 --- a/crates/noirc_frontend/src/graph/mod.rs +++ b/crates/noirc_frontend/src/graph/mod.rs @@ -10,7 +10,7 @@ use fm::FileId; use rustc_hash::{FxHashMap, FxHashSet}; use smol_str::SmolStr; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum CrateId { Root(usize), Crate(usize), diff --git a/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs b/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs index 389e6038775..57e5fb8197c 100644 --- a/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/crates/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -21,7 +21,7 @@ use fm::FileId; use iter_extended::vecmap; use noirc_errors::Span; use noirc_errors::{CustomDiagnostic, FileDiagnostic}; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::rc::Rc; use std::vec; @@ -69,9 +69,9 @@ pub struct DefCollector { pub(crate) def_map: CrateDefMap, pub(crate) collected_imports: Vec, pub(crate) collected_functions: Vec, - pub(crate) collected_types: HashMap, - pub(crate) collected_type_aliases: HashMap, - pub(crate) collected_traits: HashMap, + pub(crate) collected_types: BTreeMap, + pub(crate) collected_type_aliases: BTreeMap, + pub(crate) collected_traits: BTreeMap, pub(crate) collected_globals: Vec, pub(crate) collected_impls: ImplMap, pub(crate) collected_traits_impls: ImplMap, @@ -80,6 +80,10 @@ pub struct DefCollector { /// Maps the type and the module id in which the impl is defined to the functions contained in that /// impl along with the generics declared on the impl itself. This also contains the Span /// of the object_type of the impl, used to issue an error if the object type fails to resolve. +/// +/// Note that because these are keyed by unresolved types, the impl map is one of the few instances +/// of HashMap rather than BTreeMap. For this reason, we should be careful not to iterate over it +/// since it would be non-deterministic. type ImplMap = HashMap<(UnresolvedType, LocalModuleId), Vec<(UnresolvedGenerics, Span, UnresolvedFunctions)>>; @@ -89,9 +93,9 @@ impl DefCollector { def_map, collected_imports: vec![], collected_functions: vec![], - collected_types: HashMap::new(), - collected_type_aliases: HashMap::new(), - collected_traits: HashMap::new(), + collected_types: BTreeMap::new(), + collected_type_aliases: BTreeMap::new(), + collected_traits: BTreeMap::new(), collected_impls: HashMap::new(), collected_traits_impls: HashMap::new(), collected_globals: vec![], @@ -375,7 +379,7 @@ fn type_check_globals( /// so that expressions can access the fields of structs fn resolve_structs( context: &mut Context, - structs: HashMap, + structs: BTreeMap, crate_id: CrateId, errors: &mut Vec, ) { @@ -481,7 +485,7 @@ fn take_errors_filter_self_not_resolved(resolver: Resolver<'_>) -> Vec, + traits: BTreeMap, crate_id: CrateId, errors: &mut Vec, ) { @@ -524,7 +528,7 @@ fn resolve_struct_fields( fn resolve_type_aliases( context: &mut Context, - type_aliases: HashMap, + type_aliases: BTreeMap, crate_id: CrateId, all_errors: &mut Vec, ) { @@ -546,7 +550,7 @@ fn resolve_type_aliases( fn resolve_impls( interner: &mut NodeInterner, crate_id: CrateId, - def_maps: &HashMap, + def_maps: &BTreeMap, collected_impls: ImplMap, errors: &mut Vec, ) -> Vec<(FileId, FuncId)> { @@ -600,7 +604,7 @@ fn resolve_impls( fn resolve_free_functions( interner: &mut NodeInterner, crate_id: CrateId, - def_maps: &HashMap, + def_maps: &BTreeMap, collected_functions: Vec, self_type: Option, errors: &mut Vec, @@ -625,7 +629,7 @@ fn resolve_free_functions( fn resolve_function_set( interner: &mut NodeInterner, crate_id: CrateId, - def_maps: &HashMap, + def_maps: &BTreeMap, unresolved_functions: UnresolvedFunctions, self_type: Option, impl_generics: Vec<(Rc, Shared, Span)>, diff --git a/crates/noirc_frontend/src/hir/def_map/mod.rs b/crates/noirc_frontend/src/hir/def_map/mod.rs index c7cc02b8dac..f37ebeee06e 100644 --- a/crates/noirc_frontend/src/hir/def_map/mod.rs +++ b/crates/noirc_frontend/src/hir/def_map/mod.rs @@ -7,7 +7,7 @@ use crate::token::{Attribute, TestScope}; use arena::{Arena, Index}; use fm::{FileId, FileManager}; use noirc_errors::{FileDiagnostic, Location}; -use std::collections::HashMap; +use std::collections::BTreeMap; mod module_def; pub use module_def::*; @@ -27,7 +27,7 @@ pub const MAIN_FUNCTION: &str = "main"; // XXX: Ultimately, we want to constrain an index to be of a certain type just like in RA /// Lets first check if this is offered by any external crate /// XXX: RA has made this a crate on crates.io -#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] +#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, PartialOrd, Ord)] pub struct LocalModuleId(pub Index); impl LocalModuleId { @@ -36,7 +36,7 @@ impl LocalModuleId { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct ModuleId { pub krate: CrateId, pub local_id: LocalModuleId, @@ -49,7 +49,7 @@ impl ModuleId { } impl ModuleId { - pub fn module(self, def_maps: &HashMap) -> &ModuleData { + pub fn module(self, def_maps: &BTreeMap) -> &ModuleData { &def_maps[&self.krate].modules()[self.local_id.0] } } @@ -65,7 +65,7 @@ pub struct CrateDefMap { pub(crate) krate: CrateId, - pub(crate) extern_prelude: HashMap, + pub(crate) extern_prelude: BTreeMap, } impl CrateDefMap { @@ -100,7 +100,7 @@ impl CrateDefMap { root: LocalModuleId(root), modules, krate: crate_id, - extern_prelude: HashMap::new(), + extern_prelude: BTreeMap::new(), }; // Now we want to populate the CrateDefMap using the DefCollector diff --git a/crates/noirc_frontend/src/hir/mod.rs b/crates/noirc_frontend/src/hir/mod.rs index 5868872fa1b..1bdd3a62b72 100644 --- a/crates/noirc_frontend/src/hir/mod.rs +++ b/crates/noirc_frontend/src/hir/mod.rs @@ -9,7 +9,7 @@ use crate::hir_def::function::FuncMeta; use crate::node_interner::{FuncId, NodeInterner, StructId}; use def_map::{Contract, CrateDefMap}; use fm::FileManager; -use std::collections::HashMap; +use std::collections::BTreeMap; use self::def_map::TestFunction; @@ -19,12 +19,12 @@ use self::def_map::TestFunction; pub struct Context { pub def_interner: NodeInterner, pub crate_graph: CrateGraph, - pub(crate) def_maps: HashMap, + pub(crate) def_maps: BTreeMap, pub file_manager: FileManager, /// Maps a given (contract) module id to the next available storage slot /// for that contract. - pub storage_slots: HashMap, + pub storage_slots: BTreeMap, } #[derive(Debug, Copy, Clone)] @@ -40,10 +40,10 @@ impl Context { pub fn new(file_manager: FileManager, crate_graph: CrateGraph) -> Context { Context { def_interner: NodeInterner::default(), - def_maps: HashMap::new(), + def_maps: BTreeMap::new(), crate_graph, file_manager, - storage_slots: HashMap::new(), + storage_slots: BTreeMap::new(), } } diff --git a/crates/noirc_frontend/src/hir/resolution/import.rs b/crates/noirc_frontend/src/hir/resolution/import.rs index 8949c766881..6f3140a65d4 100644 --- a/crates/noirc_frontend/src/hir/resolution/import.rs +++ b/crates/noirc_frontend/src/hir/resolution/import.rs @@ -2,7 +2,7 @@ use iter_extended::partition_results; use noirc_errors::CustomDiagnostic; use crate::graph::CrateId; -use std::collections::HashMap; +use std::collections::BTreeMap; use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleDefId, ModuleId, PerNs}; use crate::{Ident, Path, PathKind}; @@ -52,7 +52,7 @@ impl From for CustomDiagnostic { pub fn resolve_imports( crate_id: CrateId, imports_to_resolve: Vec, - def_maps: &HashMap, + def_maps: &BTreeMap, ) -> (Vec, Vec<(PathResolutionError, LocalModuleId)>) { let def_map = &def_maps[&crate_id]; @@ -71,7 +71,7 @@ pub fn resolve_imports( } pub(super) fn allow_referencing_contracts( - def_maps: &HashMap, + def_maps: &BTreeMap, krate: CrateId, local_id: LocalModuleId, ) -> bool { @@ -81,7 +81,7 @@ pub(super) fn allow_referencing_contracts( pub fn resolve_path_to_ns( import_directive: &ImportDirective, def_map: &CrateDefMap, - def_maps: &HashMap, + def_maps: &BTreeMap, allow_contracts: bool, ) -> PathResolution { let import_path = &import_directive.path.segments; @@ -111,7 +111,7 @@ pub fn resolve_path_to_ns( fn resolve_path_from_crate_root( def_map: &CrateDefMap, import_path: &[Ident], - def_maps: &HashMap, + def_maps: &BTreeMap, allow_contracts: bool, ) -> PathResolution { resolve_name_in_module(def_map, import_path, def_map.root, def_maps, allow_contracts) @@ -121,7 +121,7 @@ fn resolve_name_in_module( def_map: &CrateDefMap, import_path: &[Ident], starting_mod: LocalModuleId, - def_maps: &HashMap, + def_maps: &BTreeMap, allow_contracts: bool, ) -> PathResolution { let mut current_mod = &def_map.modules[starting_mod.0]; @@ -185,7 +185,7 @@ fn resolve_path_name(import_directive: &ImportDirective) -> Ident { fn resolve_external_dep( current_def_map: &CrateDefMap, directive: &ImportDirective, - def_maps: &HashMap, + def_maps: &BTreeMap, allow_contracts: bool, ) -> PathResolution { // Use extern_prelude to get the dep diff --git a/crates/noirc_frontend/src/hir/resolution/path_resolver.rs b/crates/noirc_frontend/src/hir/resolution/path_resolver.rs index eb0483fbf54..4c16edd56f1 100644 --- a/crates/noirc_frontend/src/hir/resolution/path_resolver.rs +++ b/crates/noirc_frontend/src/hir/resolution/path_resolver.rs @@ -2,7 +2,7 @@ use super::import::{ allow_referencing_contracts, resolve_path_to_ns, ImportDirective, PathResolutionError, }; use crate::Path; -use std::collections::HashMap; +use std::collections::BTreeMap; use crate::graph::CrateId; use crate::hir::def_map::{CrateDefMap, LocalModuleId, ModuleDefId, ModuleId}; @@ -11,7 +11,7 @@ pub trait PathResolver { /// Resolve the given path returning the resolved ModuleDefId. fn resolve( &self, - def_maps: &HashMap, + def_maps: &BTreeMap, path: Path, ) -> Result; @@ -34,7 +34,7 @@ impl StandardPathResolver { impl PathResolver for StandardPathResolver { fn resolve( &self, - def_maps: &HashMap, + def_maps: &BTreeMap, path: Path, ) -> Result { resolve_path(def_maps, self.module_id, path) @@ -52,7 +52,7 @@ impl PathResolver for StandardPathResolver { /// Resolve the given path to a function or a type. /// In the case of a conflict, functions are given priority pub fn resolve_path( - def_maps: &HashMap, + def_maps: &BTreeMap, module_id: ModuleId, path: Path, ) -> Result { diff --git a/crates/noirc_frontend/src/hir/resolution/resolver.rs b/crates/noirc_frontend/src/hir/resolution/resolver.rs index cf0f8f80751..1ab4118099d 100644 --- a/crates/noirc_frontend/src/hir/resolution/resolver.rs +++ b/crates/noirc_frontend/src/hir/resolution/resolver.rs @@ -19,7 +19,7 @@ use crate::hir_def::expr::{ }; use crate::token::Attribute; use regex::Regex; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashSet}; use std::rc::Rc; use crate::graph::CrateId; @@ -75,7 +75,7 @@ pub struct LambdaContext { pub struct Resolver<'a> { scopes: ScopeForest, path_resolver: &'a dyn PathResolver, - def_maps: &'a HashMap, + def_maps: &'a BTreeMap, interner: &'a mut NodeInterner, errors: Vec, file: FileId, @@ -107,7 +107,7 @@ impl<'a> Resolver<'a> { pub fn new( interner: &'a mut NodeInterner, path_resolver: &'a dyn PathResolver, - def_maps: &'a HashMap, + def_maps: &'a BTreeMap, file: FileId, ) -> Resolver<'a> { Self { @@ -438,7 +438,16 @@ impl<'a> Resolver<'a> { type_alias_string }); - return self.interner.get_type_alias(id).get_type(&args); + let result = self.interner.get_type_alias(id).get_type(&args); + + // Because there is no ordering to when type aliases (and other globals) are resolved, + // it is possible for one to refer to an Error type and issue no error if it is set + // equal to another type alias. Fixing this fully requires an analysis to create a DFG + // of definition ordering, but for now we have an explicit check here so that we at + // least issue an error that the type was not found instead of silently passing. + if result != Type::Error { + return result; + } } match self.lookup_struct_or_error(path) { @@ -828,7 +837,7 @@ impl<'a> Resolver<'a> { parameters: &[Type], return_type: &Type, ) -> Vec<(String, TypeVariable)> { - let mut found = HashMap::new(); + let mut found = BTreeMap::new(); for parameter in parameters { Self::find_numeric_generics_in_type(parameter, &mut found); } @@ -836,7 +845,10 @@ impl<'a> Resolver<'a> { found.into_iter().collect() } - fn find_numeric_generics_in_type(typ: &Type, found: &mut HashMap>) { + fn find_numeric_generics_in_type( + typ: &Type, + found: &mut BTreeMap>, + ) { match typ { Type::FieldElement | Type::Integer(_, _) @@ -1508,7 +1520,7 @@ pub fn verify_mutable_reference(interner: &NodeInterner, rhs: ExprId) -> Result< mod test { use core::panic; - use std::collections::HashMap; + use std::collections::BTreeMap; use fm::FileId; use iter_extended::vecmap; @@ -1536,7 +1548,8 @@ mod test { // and functions can be forward declared fn init_src_code_resolution( src: &str, - ) -> (ParsedModule, NodeInterner, HashMap, FileId, TestPathResolver) { + ) -> (ParsedModule, NodeInterner, BTreeMap, FileId, TestPathResolver) + { let (program, errors) = parse_program(src); if errors.iter().any(|e| e.is_error()) { panic!("Unexpected parse errors in test code: {:?}", errors); @@ -1544,14 +1557,14 @@ mod test { let interner: NodeInterner = NodeInterner::default(); - let mut def_maps: HashMap = HashMap::new(); + let mut def_maps: BTreeMap = BTreeMap::new(); let file = FileId::default(); let mut modules = arena::Arena::new(); let location = Location::new(Default::default(), file); modules.insert(ModuleData::new(None, location, false)); - let path_resolver = TestPathResolver(HashMap::new()); + let path_resolver = TestPathResolver(BTreeMap::new()); def_maps.insert( CrateId::dummy_id(), @@ -1559,7 +1572,7 @@ mod test { root: path_resolver.local_module_id(), modules, krate: CrateId::dummy_id(), - extern_prelude: HashMap::new(), + extern_prelude: BTreeMap::new(), }, ); @@ -1992,12 +2005,12 @@ mod test { } } - struct TestPathResolver(HashMap); + struct TestPathResolver(BTreeMap); impl PathResolver for TestPathResolver { fn resolve( &self, - _def_maps: &HashMap, + _def_maps: &BTreeMap, path: Path, ) -> Result { // Not here that foo::bar and hello::foo::bar would fetch the same thing diff --git a/crates/noirc_frontend/src/hir/type_check/mod.rs b/crates/noirc_frontend/src/hir/type_check/mod.rs index 8596a9cc28c..d17fbdc17de 100644 --- a/crates/noirc_frontend/src/hir/type_check/mod.rs +++ b/crates/noirc_frontend/src/hir/type_check/mod.rs @@ -167,7 +167,7 @@ impl<'interner> TypeChecker<'interner> { /// We can either build a test apparatus or pass raw code through the resolver #[cfg(test)] mod test { - use std::collections::HashMap; + use std::collections::{BTreeMap, HashMap}; use std::vec; use fm::FileId; @@ -365,7 +365,7 @@ mod test { impl PathResolver for TestPathResolver { fn resolve( &self, - _def_maps: &HashMap, + _def_maps: &BTreeMap, path: Path, ) -> Result { // Not here that foo::bar and hello::foo::bar would fetch the same thing @@ -415,7 +415,7 @@ mod test { path_resolver.insert_func(name.to_owned(), id); } - let mut def_maps: HashMap = HashMap::new(); + let mut def_maps = BTreeMap::new(); let file = FileId::default(); let mut modules = arena::Arena::new(); @@ -428,7 +428,7 @@ mod test { root: path_resolver.local_module_id(), modules, krate: CrateId::dummy_id(), - extern_prelude: HashMap::new(), + extern_prelude: BTreeMap::new(), }, ); diff --git a/crates/noirc_frontend/src/monomorphization/mod.rs b/crates/noirc_frontend/src/monomorphization/mod.rs index 7a25c5e6b77..58dc619952b 100644 --- a/crates/noirc_frontend/src/monomorphization/mod.rs +++ b/crates/noirc_frontend/src/monomorphization/mod.rs @@ -1327,7 +1327,7 @@ fn undo_instantiation_bindings(bindings: TypeBindings) { #[cfg(test)] mod tests { - use std::collections::HashMap; + use std::collections::{BTreeMap, HashMap}; use fm::FileId; use iter_extended::vecmap; @@ -1372,7 +1372,7 @@ mod tests { path_resolver.insert_func(name.to_owned(), id); } - let mut def_maps: HashMap = HashMap::new(); + let mut def_maps = BTreeMap::new(); let file = FileId::default(); let mut modules = arena::Arena::new(); @@ -1385,7 +1385,7 @@ mod tests { root: path_resolver.local_module_id(), modules, krate: CrateId::dummy_id(), - extern_prelude: HashMap::new(), + extern_prelude: BTreeMap::new(), }, ); @@ -1424,7 +1424,7 @@ mod tests { impl PathResolver for TestPathResolver { fn resolve( &self, - _def_maps: &HashMap, + _def_maps: &BTreeMap, path: crate::Path, ) -> Result { // Not here that foo::bar and hello::foo::bar would fetch the same thing diff --git a/crates/noirc_frontend/src/node_interner.rs b/crates/noirc_frontend/src/node_interner.rs index d72b8d9d949..24015d76a07 100644 --- a/crates/noirc_frontend/src/node_interner.rs +++ b/crates/noirc_frontend/src/node_interner.rs @@ -139,7 +139,7 @@ impl FuncId { } } -#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] +#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone, PartialOrd, Ord)] pub struct StructId(ModuleId); impl StructId { @@ -163,7 +163,7 @@ impl StructId { } } -#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] +#[derive(Debug, Eq, PartialEq, Hash, Copy, Clone, PartialOrd, Ord)] pub struct TypeAliasId(pub usize); impl TypeAliasId { @@ -172,7 +172,7 @@ impl TypeAliasId { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct TraitId(pub ModuleId); impl TraitId { From ed24448781112c1886d90aa8a984a31b57f7cdff Mon Sep 17 00:00:00 2001 From: kevaundray Date: Tue, 5 Sep 2023 19:55:14 +0100 Subject: [PATCH 6/9] chore: Temporarily disable `noir_wasm` test (#2566) --- .github/workflows/wasm.yml | 84 +++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index cef22aafbbd..1e28f84cfa3 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -113,45 +113,45 @@ jobs: path: ${{ env.UPLOAD_PATH }} retention-days: 3 - test: - needs: [build-wasm, build-nargo] - name: Test noir_wasm - runs-on: ubuntu-latest - steps: - - name: Checkout noir-lang/noir - uses: actions/checkout@v4 - - - name: Download wasm package artifact - uses: actions/download-artifact@v3 - with: - name: noir_wasm - path: ./crates/wasm/result - - - name: Download nargo binary - uses: actions/download-artifact@v3 - with: - name: nargo - path: ./nargo - - - name: Compile test program with Nargo CLI - working-directory: ./crates/wasm/noir-script - run: | - nargo_binary=${{ github.workspace }}/nargo/nargo - chmod +x $nargo_binary - $nargo_binary compile - - - name: Install dependencies - working-directory: ./crates/wasm - run: yarn install - - - name: Install playwright deps - working-directory: ./crates/wasm - run: | - npx playwright install - npx playwright install-deps - - - name: Run tests - working-directory: ./crates/wasm - run: | - yarn test:browser - yarn test:node + # test: + # needs: [build-wasm, build-nargo] + # name: Test noir_wasm + # runs-on: ubuntu-latest + # steps: + # - name: Checkout noir-lang/noir + # uses: actions/checkout@v4 + + # - name: Download wasm package artifact + # uses: actions/download-artifact@v3 + # with: + # name: noir_wasm + # path: ./crates/wasm/result + + # - name: Download nargo binary + # uses: actions/download-artifact@v3 + # with: + # name: nargo + # path: ./nargo + + # - name: Compile test program with Nargo CLI + # working-directory: ./crates/wasm/noir-script + # run: | + # nargo_binary=${{ github.workspace }}/nargo/nargo + # chmod +x $nargo_binary + # $nargo_binary compile + + # - name: Install dependencies + # working-directory: ./crates/wasm + # run: yarn install + + # - name: Install playwright deps + # working-directory: ./crates/wasm + # run: | + # npx playwright install + # npx playwright install-deps + + # - name: Run tests + # working-directory: ./crates/wasm + # run: | + # yarn test:browser + # yarn test:node From c67cd7df9b5b47a554cc35a50f5bb80d1a4a12f0 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Tue, 5 Sep 2023 20:34:17 +0100 Subject: [PATCH 7/9] fix: Black box func slice handling (#2562) --- .../acir_artifacts/schnorr/target/acir.gz | Bin 2212 -> 2204 bytes .../acir_artifacts/schnorr/target/witness.gz | Bin 822 -> 819 bytes .../double_verify_proof/src/main.nr | 23 +-- .../brillig/brillig_gen/brillig_black_box.rs | 157 ++++-------------- .../src/brillig/brillig_gen/brillig_block.rs | 23 ++- .../ssa/acir_gen/acir_ir/generated_acir.rs | 73 +++----- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 23 ++- 7 files changed, 104 insertions(+), 195 deletions(-) diff --git a/crates/nargo_cli/tests/acir_artifacts/schnorr/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/schnorr/target/acir.gz index 67a7af6022f58460b08dcee751c90f91dc24cab7..f2901f3cc9149d4553c46bd76c8a41f190997585 100644 GIT binary patch delta 1772 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 literal 822 zcmV-61Ihd!iwFP!00002|E-$Uj@(KRKy#UynVFj5Qka<;+6`f5W@d%+wQ;nGviq7j zmPVR~nWOS?b#=Myd!vSqXZp{WN8iPO$Fm$uKF6`t^BhaRz_HAW9Lv7MvE0iX%fG_0 z!mAuBzV`GiDU{H{2rHcMB8d38b^f^)AWw}y)1;;NeSRSdUp z3yZO|bzH6{&z)llV2>HOwJrbV>T3Rn+iUf|T%FMWao17(&&6d%gFVw2t_KKXF;*$# zxVXf4uwR|P#ib{5HM*O`)xtKJt2u587nhp~_BqqQ{F=_~+i3<@qy0>-Mz>kuyl^%+ z$D9MsSLcFr-+AD?a6ULEUjWYU7lO|f7J<(@7K6`WmJDNQ;f$$X)xK3vLd7oFzN_k7 zkfEO-+oFQjHJIRI7rlu6omrL5M%^C8wRCt~T`1AGRAcZ`Dl4q_)|&orA*+(3Ej8N| zVy-@yl8tmpdutw!tD=;hSq7fta*(xxW2Kd#`&FR()u696AS(^PY9kNVf$lTtzJR_e z$ZDK>zZP`A4s^dB^tAzGZRFgCO`!YDp!+SLudN_!8|OZ52i@-g-R}f_?E+c5IrnJ~ z=zcHgejn&-Kgc@3x$h2w?hk?P4}-prfUKjO`+N*^e;jmw0`zqfWS!#Nm(!s8Gobsk zps#Zv>pbVaUI5)+1l?Z(eO(4wS2*|WDtM244V;@?2U#~pVebTrn@^vs@^P-#zPE2d z$Xf%mLak{i&f5dAN^SDV8oD#cdXyvA<6Y4GJ;GNUa({oIa~$dG0ZVX9TXZb|0FM*5 AWB>pF diff --git a/crates/nargo_cli/tests/execution_success/double_verify_proof/src/main.nr b/crates/nargo_cli/tests/execution_success/double_verify_proof/src/main.nr index 82418618f26..39b8c142ace 100644 --- a/crates/nargo_cli/tests/execution_success/double_verify_proof/src/main.nr +++ b/crates/nargo_cli/tests/execution_success/double_verify_proof/src/main.nr @@ -8,29 +8,22 @@ fn main( input_aggregation_object : [Field; 16], proof_b : [Field; 94], ) -> pub [Field; 16] { - - let verification_key : [Field] = verification_key; - let proof : [Field] = proof; - let proof_b : [Field] = proof_b; - let public_inputs : [Field] = public_inputs; - - let output_aggregation_object_a = std::verify_proof( - verification_key, - proof, - public_inputs, - key_hash, + verification_key.as_slice(), + proof.as_slice(), + public_inputs.as_slice(), + key_hash, input_aggregation_object ); let output_aggregation_object = std::verify_proof( - verification_key, - proof_b, - public_inputs, + verification_key.as_slice(), + proof_b.as_slice(), + public_inputs.as_slice(), key_hash, output_aggregation_object_a ); - + let mut output = [0; 16]; for i in 0..16 { output[i] = output_aggregation_object[i]; diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 7180467aff7..16df0687a1a 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -16,24 +16,10 @@ pub(crate) fn convert_black_box_call( ) { match bb_func { BlackBoxFunc::SHA256 => { - if let ([..], [RegisterOrMemory::HeapArray(result_array)]) = + if let ([message], [RegisterOrMemory::HeapArray(result_array)]) = (function_arguments, function_results) { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let message = if function_arguments.len() > 1 { - &function_arguments[1] - } else { - &function_arguments[0] - }; - let message_vector = match message { - RegisterOrMemory::HeapArray(message_array) => { - brillig_context.array_to_vector(message_array) - } - RegisterOrMemory::HeapVector(message_vector) => *message_vector, - _ => unreachable!("ICE: SHA256 expects the message to be an array or a vector"), - }; + let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::Sha256 { message: message_vector, output: *result_array, @@ -43,26 +29,10 @@ pub(crate) fn convert_black_box_call( } } BlackBoxFunc::Blake2s => { - if let ([..], [RegisterOrMemory::HeapArray(result_array)]) = + if let ([message], [RegisterOrMemory::HeapArray(result_array)]) = (function_arguments, function_results) { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let message = if function_arguments.len() > 1 { - &function_arguments[1] - } else { - &function_arguments[0] - }; - let message_vector = match message { - RegisterOrMemory::HeapArray(message_array) => { - brillig_context.array_to_vector(message_array) - } - RegisterOrMemory::HeapVector(message_vector) => *message_vector, - _ => { - unreachable!("ICE: Blake2s expects the message to be an array or a vector") - } - }; + let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::Blake2s { message: message_vector, output: *result_array, @@ -73,27 +43,13 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::Keccak256 => { if let ( - [.., RegisterOrMemory::RegisterIndex(array_size)], + [message, RegisterOrMemory::RegisterIndex(array_size)], [RegisterOrMemory::HeapArray(result_array)], ) = (function_arguments, function_results) { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let message = if function_arguments.len() > 2 { - &function_arguments[1] - } else { - &function_arguments[0] - }; - let message_vector = match message { - RegisterOrMemory::HeapArray(message_array) => { - HeapVector { size: *array_size, pointer: message_array.pointer } - } - RegisterOrMemory::HeapVector(message_vector) => *message_vector, - _ => unreachable!( - "ICE: Keccak256 expects the message to be an array or a vector" - ), - }; + let mut message_vector = convert_array_or_vector(brillig_context, message, bb_func); + message_vector.size = *array_size; + brillig_context.black_box_op_instruction(BlackBoxOp::Keccak256 { message: message_vector, output: *result_array, @@ -103,26 +59,10 @@ pub(crate) fn convert_black_box_call( } } BlackBoxFunc::HashToField128Security => { - if let ([..], [RegisterOrMemory::RegisterIndex(result_register)]) = + if let ([message], [RegisterOrMemory::RegisterIndex(result_register)]) = (function_arguments, function_results) { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let message = if function_arguments.len() > 1 { - &function_arguments[1] - } else { - &function_arguments[0] - }; - let message_vector = match message { - RegisterOrMemory::HeapArray(message_array) => { - brillig_context.array_to_vector(message_array) - } - RegisterOrMemory::HeapVector(message_vector) => { - *message_vector - } - _ => unreachable!("ICE: HashToField128Security expects the message to be an array or a vector"), - }; + let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::HashToField128Security { message: message_vector, output: *result_register, @@ -133,27 +73,12 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::EcdsaSecp256k1 => { if let ( - [RegisterOrMemory::HeapArray(public_key_x), RegisterOrMemory::HeapArray(public_key_y), RegisterOrMemory::HeapArray(signature), ..], + [RegisterOrMemory::HeapArray(public_key_x), RegisterOrMemory::HeapArray(public_key_y), RegisterOrMemory::HeapArray(signature), message], [RegisterOrMemory::RegisterIndex(result_register)], ) = (function_arguments, function_results) { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let message = if function_arguments.len() > 4 { - &function_arguments[4] - } else { - &function_arguments[3] - }; - let message_hash_vector = match message { - RegisterOrMemory::HeapArray(message_hash) => { - brillig_context.array_to_vector(message_hash) - } - RegisterOrMemory::HeapVector(message_hash_vector) => *message_hash_vector, - _ => unreachable!( - "ICE: EcdsaSecp256k1 expects the message to be an array or a vector" - ), - }; + let message_hash_vector = + convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::EcdsaSecp256k1 { hashed_msg: message_hash_vector, public_key_x: *public_key_x, @@ -169,27 +94,11 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::Pedersen => { if let ( - [.., RegisterOrMemory::RegisterIndex(domain_separator)], + [message, RegisterOrMemory::RegisterIndex(domain_separator)], [RegisterOrMemory::HeapArray(result_array)], ) = (function_arguments, function_results) { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let message = if function_arguments.len() > 2 { - &function_arguments[1] - } else { - &function_arguments[0] - }; - let message_vector = match message { - RegisterOrMemory::HeapArray(message_array) => { - brillig_context.array_to_vector(message_array) - } - RegisterOrMemory::HeapVector(message_vector) => *message_vector, - _ => { - unreachable!("ICE: Pedersen expects the message to be an array or a vector") - } - }; + let message_vector = convert_array_or_vector(brillig_context, message, bb_func); brillig_context.black_box_op_instruction(BlackBoxOp::Pedersen { inputs: message_vector, domain_separator: *domain_separator, @@ -201,27 +110,11 @@ pub(crate) fn convert_black_box_call( } BlackBoxFunc::SchnorrVerify => { if let ( - [RegisterOrMemory::RegisterIndex(public_key_x), RegisterOrMemory::RegisterIndex(public_key_y), RegisterOrMemory::HeapArray(signature), ..], + [RegisterOrMemory::RegisterIndex(public_key_x), RegisterOrMemory::RegisterIndex(public_key_y), RegisterOrMemory::HeapArray(signature), message], [RegisterOrMemory::RegisterIndex(result_register)], ) = (function_arguments, function_results) { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let message = if function_arguments.len() > 4 { - &function_arguments[4] - } else { - &function_arguments[3] - }; - let message_hash = match message { - RegisterOrMemory::HeapArray(message_hash) => { - brillig_context.array_to_vector(message_hash) - } - RegisterOrMemory::HeapVector(message_hash) => *message_hash, - _ => unreachable!( - "ICE: Schnorr verify expects the message to be an array or a vector" - ), - }; + let message_hash = convert_array_or_vector(brillig_context, message, bb_func); let signature = brillig_context.array_to_vector(signature); brillig_context.black_box_op_instruction(BlackBoxOp::SchnorrVerify { public_key_x: *public_key_x, @@ -253,3 +146,19 @@ pub(crate) fn convert_black_box_call( _ => unimplemented!("ICE: Black box function {:?} is not implemented", bb_func), } } + +fn convert_array_or_vector( + brillig_context: &mut BrilligContext, + array_or_vector: &RegisterOrMemory, + bb_func: &BlackBoxFunc, +) -> HeapVector { + match array_or_vector { + RegisterOrMemory::HeapArray(array) => brillig_context.array_to_vector(array), + RegisterOrMemory::HeapVector(vector) => *vector, + _ => unreachable!( + "ICE: {} expected an array or a vector, but got {:?}", + bb_func.name(), + array_or_vector + ), + } +} diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 15195fc4dcb..a62c8e72498 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -308,8 +308,29 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_function_call(*func_id, arguments, dfg, instruction_id); } Value::Intrinsic(Intrinsic::BlackBox(bb_func)) => { + // Slices are represented as a tuple of (length, slice contents). + // We must check the inputs to determine if there are slices + // and make sure that we pass the correct inputs to the black box function call. + // The loop below only keeps the slice contents, so that + // setting up a black box function with slice inputs matches the expected + // number of arguments specified in the function signature. + let mut arguments_no_slice_len = Vec::new(); + for (i, arg) in arguments.iter().enumerate() { + if matches!(dfg.type_of_value(*arg), Type::Numeric(_)) { + if i < arguments.len() - 1 { + if !matches!(dfg.type_of_value(arguments[i + 1]), Type::Slice(_)) { + arguments_no_slice_len.push(*arg); + } + } else { + arguments_no_slice_len.push(*arg); + } + } else { + arguments_no_slice_len.push(*arg); + } + } + let function_arguments = - vecmap(arguments, |arg| self.convert_ssa_value(*arg, dfg)); + vecmap(&arguments_no_slice_len, |arg| self.convert_ssa_value(*arg, dfg)); let function_results = dfg.instruction_results(instruction_id); let function_results = vecmap(function_results, |result| { self.allocate_external_call_result(*result, dfg) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index 8304ce1fbee..a914d32a8f7 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -149,58 +149,30 @@ impl GeneratedAcir { BlackBoxFuncCall::XOR { lhs: inputs[0][0], rhs: inputs[1][0], output: outputs[0] } } BlackBoxFunc::RANGE => BlackBoxFuncCall::RANGE { input: inputs[0][0] }, - BlackBoxFunc::SHA256 => { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let inputs = if inputs.len() > 1 { inputs[1].clone() } else { inputs[0].clone() }; - BlackBoxFuncCall::SHA256 { inputs, outputs } - } + BlackBoxFunc::SHA256 => BlackBoxFuncCall::SHA256 { inputs: inputs[0].clone(), outputs }, BlackBoxFunc::Blake2s => { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let inputs = if inputs.len() > 1 { inputs[1].clone() } else { inputs[0].clone() }; - BlackBoxFuncCall::Blake2s { inputs, outputs } - } - BlackBoxFunc::HashToField128Security => { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let inputs = if inputs.len() > 1 { inputs[1].clone() } else { inputs[0].clone() }; - BlackBoxFuncCall::HashToField128Security { inputs, output: outputs[0] } + BlackBoxFuncCall::Blake2s { inputs: inputs[0].clone(), outputs } } + BlackBoxFunc::HashToField128Security => BlackBoxFuncCall::HashToField128Security { + inputs: inputs[0].clone(), + output: outputs[0], + }, BlackBoxFunc::SchnorrVerify => { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let message = if inputs.len() > 4 { inputs[4].clone() } else { inputs[3].clone() }; BlackBoxFuncCall::SchnorrVerify { public_key_x: inputs[0][0], public_key_y: inputs[1][0], // Schnorr signature is an r & s, 32 bytes each signature: inputs[2].clone(), - message, + message: inputs[3].clone(), output: outputs[0], } } - BlackBoxFunc::Pedersen => { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let inputs = if inputs.len() > 1 { inputs[1].clone() } else { inputs[0].clone() }; - BlackBoxFuncCall::Pedersen { - inputs, - outputs: (outputs[0], outputs[1]), - domain_separator: constants[0].to_u128() as u32, - } - } + BlackBoxFunc::Pedersen => BlackBoxFuncCall::Pedersen { + inputs: inputs[0].clone(), + outputs: (outputs[0], outputs[1]), + domain_separator: constants[0].to_u128() as u32, + }, BlackBoxFunc::EcdsaSecp256k1 => { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let hashed_message = - if inputs.len() > 4 { inputs[4].clone() } else { inputs[3].clone() }; BlackBoxFuncCall::EcdsaSecp256k1 { // 32 bytes for each public key co-ordinate public_key_x: inputs[0].clone(), @@ -208,16 +180,11 @@ impl GeneratedAcir { // (r,s) are both 32 bytes each, so signature // takes up 64 bytes signature: inputs[2].clone(), - hashed_message, + hashed_message: inputs[3].clone(), output: outputs[0], } } BlackBoxFunc::EcdsaSecp256r1 => { - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - let hashed_message = - if inputs.len() > 4 { inputs[4].clone() } else { inputs[3].clone() }; BlackBoxFuncCall::EcdsaSecp256r1 { // 32 bytes for each public key co-ordinate public_key_x: inputs[0].clone(), @@ -225,7 +192,7 @@ impl GeneratedAcir { // (r,s) are both 32 bytes each, so signature // takes up 64 bytes signature: inputs[2].clone(), - hashed_message, + hashed_message: inputs[3].clone(), output: outputs[0], } } @@ -245,13 +212,11 @@ impl GeneratedAcir { } }; - // Slices are represented as a tuple of (length, slice contents). - // We must check the number of inputs to differentiate between arrays and slices - // and make sure that we pass the correct inputs to the function call. - // `inputs` is cloned into a vector before being popped to find the `var_message_size` - // so we still check `inputs` against its original size passed into `call_black_box` - let inputs = if inputs.len() > 2 { inputs[1].clone() } else { inputs[0].clone() }; - BlackBoxFuncCall::Keccak256VariableLength { inputs, var_message_size, outputs } + BlackBoxFuncCall::Keccak256VariableLength { + inputs: inputs[0].clone(), + var_message_size, + outputs, + } } BlackBoxFunc::RecursiveAggregation => { let has_previous_aggregation = self.opcodes.iter().any(|op| { diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/mod.rs b/crates/noirc_evaluator/src/ssa/acir_gen/mod.rs index d5e1df64a6b..b69376c573c 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -1034,7 +1034,28 @@ impl Context { ) -> Result, RuntimeError> { match intrinsic { Intrinsic::BlackBox(black_box) => { - let inputs = vecmap(arguments, |arg| self.convert_value(*arg, dfg)); + // Slices are represented as a tuple of (length, slice contents). + // We must check the inputs to determine if there are slices + // and make sure that we pass the correct inputs to the black box function call. + // The loop below only keeps the slice contents, so that + // setting up a black box function with slice inputs matches the expected + // number of arguments specified in the function signature. + let mut arguments_no_slice_len = Vec::new(); + for (i, arg) in arguments.iter().enumerate() { + if matches!(dfg.type_of_value(*arg), Type::Numeric(_)) { + if i < arguments.len() - 1 { + if !matches!(dfg.type_of_value(arguments[i + 1]), Type::Slice(_)) { + arguments_no_slice_len.push(*arg); + } + } else { + arguments_no_slice_len.push(*arg); + } + } else { + arguments_no_slice_len.push(*arg); + } + } + + 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) From 9be750a713485ff84b111128db62b56fc0d0c5a5 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 5 Sep 2023 20:45:42 +0100 Subject: [PATCH 8/9] feat(ssa): Replace values which have previously been constrained with simplified value (#2483) Co-authored-by: jfecher --- .../acir_artifacts/6_array/target/acir.gz | Bin 7476 -> 7215 bytes .../acir_artifacts/6_array/target/witness.gz | Bin 2781 -> 2705 bytes .../array_dynamic/target/acir.gz | Bin 1887 -> 1804 bytes .../array_dynamic/target/witness.gz | Bin 609 -> 594 bytes .../brillig_arrays/target/acir.gz | Bin 512 -> 420 bytes .../brillig_assert/target/acir.gz | Bin 371 -> 356 bytes .../brillig_calls/target/acir.gz | Bin 1075 -> 1071 bytes .../brillig_calls_array/target/acir.gz | Bin 978 -> 942 bytes .../brillig_nested_slices/target/acir.gz | Bin 5381 -> 4974 bytes .../brillig_oracle/target/acir.gz | Bin 2311 -> 2205 bytes .../brillig_slices/target/acir.gz | Bin 5472 -> 4878 bytes .../target/acir.gz | Bin 427 -> 407 bytes .../brillig_to_le_bytes/target/acir.gz | Bin 1661 -> 924 bytes .../double_verify_proof/target/witness.gz | Bin 8258 -> 8388 bytes .../to_bytes_consistent/target/acir.gz | Bin 3769 -> 793 bytes .../to_bytes_consistent/target/witness.gz | Bin 841 -> 268 bytes .../acir_artifacts/to_le_bytes/target/acir.gz | Bin 3594 -> 687 bytes .../to_le_bytes/target/witness.gz | Bin 841 -> 268 bytes .../acir_artifacts/tuples/target/acir.gz | Bin 397 -> 107 bytes .../acir_artifacts/tuples/target/witness.gz | Bin 159 -> 49 bytes .../src/ssa/opt/constant_folding.rs | 139 ++++++++++++++++-- 21 files changed, 130 insertions(+), 9 deletions(-) diff --git a/crates/nargo_cli/tests/acir_artifacts/6_array/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/6_array/target/acir.gz index 5cc3eae3234f3a7cc418c61e91d93e3ffb40b8a5..05d33bd7ce3bceffb0cefd41e8b8b11b7b0acdff 100644 GIT binary patch literal 7215 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 I1qj4{0h`xzaR2}S literal 2781 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 diff --git a/crates/nargo_cli/tests/acir_artifacts/array_dynamic/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/array_dynamic/target/acir.gz index e74d7f1d7943613e630ae28ffef43027f146e0e9..78e27fb7119de193a32ff155c5b62f3568f65b89 100644 GIT binary patch literal 1804 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 literal 609 zcmV-n0-pUJiwFP!00002|E-x-uN5&AMsas{cWpbBUG(Da?o6jG?iK>cg$MZE4BYc@ z-dU5J_Kfd;BZL3yzaB3WIF_5pvARhhYcj{GQ!rMOreZABPUBc= zI>*v8IF^~ov6@*N%gzSf&jH=f1>MgB-OmTzF93Zl1brY%R0!*vZ{u7uzvxX>lvT5+b|%Ux zRHr4^Ahon&{xR(m@LgRBvX*iCs#y-YUje#b3Hn+EzW1v+R$K$RUkkcl2fAMmy59iq zg&Ve$md(7gxU2hf**drsu`!n_acaX)x(asc#o5bW^~IKvzU?_fs2`SA!?*HLhf zJ_eovj)U*S39!eL;MzU~)^!^6bp~A9XE9dw=P*{R=P{O17cf>*7diKG33PuMWL*Js zyb9)c4b1U6nBxu5*G(|TTVP$c!5r^^Io<_xya)DpAI$LqnBzmR$46j}kHH*Uu&xB= z*nv4_FvkM=s$h;!K-N==Wqf`%#4=e-qjUCNM552B)maSV0>-*53H`s&%txy3-BJ`C3p|;3hePU$a(|LqHjU>??CtOL0=!hx#J_q`UK8t vpF!3a(EV5N8`w9nuJ7QyJxZ~3bU(1Vviix@m4AWme}k+)_2b=~yd?ktdd)DL diff --git a/crates/nargo_cli/tests/acir_artifacts/brillig_arrays/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/brillig_arrays/target/acir.gz index d132483ccf035a5f5d2c11b71bf1555c700e2483..1077aca8e7bfb5b8878c6c808eb1fa3ed4bdc9a0 100644 GIT binary patch literal 420 zcmV;V0bBkbiwFP!00000|Ls`IPQ)+_^fukTA2+VtxFNL^PFy1R|9^r&Mx9NHIA9-u zwNyEY+st%gTiY!~#L1_fqsRR8eid=<;vDO^M`$gWkAC@?ttY*`7Aua$FW~45IKsy0 z+n6V86^*?P{#NPhvxJ;S-cONtsf;0nA*2;>I>~FWl3hcu!(-+BOTq+>qxcYgIOCdh z*FMzs+E{Xq|GlxiM*r6ui&MrhXjV@Kjc04+vH^<sk{CGfavL;7)$n~Y1QxCj?FAP&%^Cl1iWB40<+1egu+LHse%#DdEt zxh7mY;4+aW7Wq1nCL`fP6U3hrO)R*~l54`X11>XZVo^IYX#z~H9mHQq6Z4NEk;{Kz OzOpyCjZhZC5dZ*p0MY&c literal 512 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 diff --git a/crates/nargo_cli/tests/acir_artifacts/brillig_calls_array/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/brillig_calls_array/target/acir.gz index 3c8aa141382023f8b3af72a75b9560d64f19bab4..12986ecc1c61997885e6b502fc955d7fecfb5f45 100644 GIT binary patch literal 942 zcmV;f15x}RiwFP!00000|LvPgZrd;rhDT3Z?)foAaZRyn*vjoJaF{GS`bl{b>FLkj`ZY z(o7iVxc$G-1$u3@t{B5Nz!)hq25`M&IQ~4x**sn_q;NdyaP+CZPHh6L88CBy>gQi! zNjG&OlkR`Y>O9l)CX_3$h#|P&b-9JHoY^lR#V@o;gd*Yz)XlI0Twv_`z z>;X$?VM%pare_tuV+gKK3LMO|g1oh|CZ>(d!m$Ppwx5A^SZ8Bl&E~pT&+wPJ{9DsT zW#KP@pYQVu_$$HBtOYRFqMk`>=HnXDc)T>Af$3|k+t+E#Brn)!<20w!X9AIvu{+&I ziO^4u-;7?y0y*B`s5{h>cTO<`CT&gYEpZQ)EJ{G8*rzF_9bQBCh>(rDrh zolhDgD8mzlYR+FN^O!bxf`+=RKo@4giJbBTb{jzZtP9)CKo>4^Cv?e`c}yF&O`05H zX2BP}^1`kUpncYb?UtYmm-#4k(H_5-Hm(X~JFiVj3lXyhzOcj|u_PX`q#m)XJYrdU z#FBZ$l6%Bbdc+c3ndQe9Nnd%u zQhLOad&H7?#Ip8?W#th|>Jdxg5lie5OXLwtXklq|S?+POp4VIaK4M!Dl=%isjy`zx z_~DvBCk!JTJN$Uua=Qdt5ZEaoAJ>PjKfaB0y4E4f@xrRZdT9^9g`)xq7P9CfHS>YR zwFAe$u()uc@JPasihqDU3>2|5Ozj5$Nkel@LiK7_J}3& zh$XbJC_5QV?@n|WlKbj5CnE=Y+tZ%EZI2N5w%L9G+F_lIh1JBRsOMn5IPJ|h7Ji&7 z@*J@N{zmZ2wKF1W77VA!@8DO4hSKwPjl^H3<>T=ywQSe&HA|ARUTyG^UfWT_oB^<1c`G zu0xQg!)}b5{|jwkudl`xV|W9MkwwM;?sp8=AI4aX^94f+*E>5LU20!XO#-Y6n0Y+a z%P%+N>o$?)dxm<(ehFkDOK@ct1q=jvkSW3Gr!!uFQsZL6e&Cf^W zSSOXxNdfX$C$)j)-Y!e0<=oM6xb$7V2bKrBEW>mB2(p-q<>XL~@BT--9K-#25aZ`G z^8GDqenYJFm01_(tM&e= zZ~J!LuRksOt~>OrezVxJbi&w^4mRo>cxXwGF7u)mq+{RUIScfiEnvM=Xg)EU8B< zGmlv29?O zH|a|cSPG9=GLKl4M=W!XSY{rvq#m&(9}>Z z6YV?P)BXYF@)^K>QbRo)yY0R1K*-ra8uz;c!FNrT*dvz6BbLy>V%aHd_;#X$mplhC zIfXemix|#mOnbU`7Qym!&>gl}7+7^&h;|Ov_rqCAZQ#eXJ+J9&;I9S0-0MJRmKyTd zX~pDFz-5zj+T@(JpvgHcpvgJS6m%bxbJ}%TC+D=$d5GxvA5`bUFS3eihq5&Q0PmUZ AEdT%j diff --git a/crates/nargo_cli/tests/acir_artifacts/brillig_nested_slices/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/brillig_nested_slices/target/acir.gz index 2a59ac10946731064f89e808c46ace30c517a506..321a0ddc970a9fc5be7545ee692c509832a56328 100644 GIT binary patch literal 4974 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 literal 5381 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 P(N}DZOy`&3H*fk626UVw diff --git a/crates/nargo_cli/tests/acir_artifacts/brillig_oracle/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/brillig_oracle/target/acir.gz index 91305e16a1180b65812f1a408558efbb512bef11..94f6a5d96d24d05b437de263a5f57e8bbdea4db3 100644 GIT binary patch literal 2205 zcmaJ?dpMJO97iq{Q%_2lId*!~x-m-`%B6Ewx^OBa#)@*AmPKxJTz2q0YaS{j-05-{{=S!}*sQ8`s~gDwwinqwr5v~pkPYi7;F#uz@b zyWCYfktRyqOQ&tiwCu1N5wXm=Wa+*#Wsxv^az|P0M0Jl;zud#Y!nDq*b&vDp%a89E z@x8*&)%6wggwuRYf|;D5yUR-l$Bmk4K7i9BjrCEMO>3GeCWy8ZKZggMGyFz>p88>E zv6-RUwU{^w?z^PbJyq=AY+_oJ+PHHpU?E;D&R0n=@BMA6LTWds z-`p&D?`HGP!%TcId}T1FxjAwLhc@>)<>|ck;7doAg+w)8*JqiqzC4`56M zL@;nefDC96JTTCJj!`*x6UUWK5;q|OMSFZk(@x*RzKWD`$P$ix@+Ni?K-wl~Q$w2P zTJ_^Z(_7;yVecw9oU zpP6`JI3*Mc;93yCzLckYu;CCAz@$YLaGnMroyw@NPIt5}zJyqNrDpW7%sKW0GWqhs5ylsRRNJTUg_jyu&|vGhgskm_NR z@`7_>&8xqtH*tfFx4mbVy<%4>yl9&^Eg!NS$ZpH^LG%x(L~bnTfMdcd1=}_xE}9GT zzxpLd$0+mET^MG}8YBWMq2n5l0>_mU@5wG4JRTA4K5aU^{n5@bBYnKF6B{mw-V10! zn_hM%k5Hj4(Q;0xSqtyZ!(kT>g#ntl^b3O>=EuW+TB0sB+Co3 z6nIk$^Xk)on1axBrDQz0o6PLdSTx2McR_^XH-S+0LZO_s?yOgQPeM5)0uI(Xx$e$X^v1_;L)XCx z&_g?A+zR;V14^i|v@owkhmf1!zL^Vn>wz9}06LYH#i>!5pms(|04m#YfGR=gLorOv zeDZSdhxid3=m_oxjyE;(4P~DFotlU>NCzF@0-YkDB4xJkqMS=X-)kC``&okb*+cMq zbF{PQfPg6CB9Q5eZIGQI!PskE$wV>B034$;VBlk+))jN4(hDa1@GPj&T!;bv{GSpjV=X7?cV&+)E3$$?Mn zJKA%8P(YT0`%SgP9%kzg@_14ci_!QIE>sd8#7bt3CJZYPja2;>U>*UqweA382Zeyb zQi5(|K`VY+0B6tz9Y})QR!nx=f{7bDDFoC#Kj5Cq9ju5qgI9Q=YRv`%=2SKFx*Q%= z2Z?!u7U+m;{>MK*puu-kfmZ2vG02Ai>h}cStwGiQ`iBAjE#eqN#WH0ba_3+B6Ydq% S%=o7M(C4W<0(T$M(D(1 zbwoJ|BjmwsjPjMq<}8$Rn#RsJAJ~aVW`3W~81w)0@p`|G?`O1A<#$MblGcKs)9{`L zI9#;#Ba-vLU;AD-Ir|x*Ya(Zdod#=y9U4a&k>wu8Zx+vdG~BCD_bYOy!#2?6@m__! zD9o`A+hgAaxKtb6_Vt(Ym+-kv1 zcj2?8qLc~U!aCk^uQ;W*Xdpu?)=~6MH^{dZ>x2~q+&s3)#?QQZTTV?RS8DFtOq%}V z0{3Vshd;6~ySl%eVsPjYcP?boul;K5$2+G?)KAic7NNJTA7!eopRQ0jo)cou88~~C zA(U5LC8G4+jI9{2Ys|O?3@r6_vMwC2kKfa?)8v{3>9(~`;**ymBb!DVU|ip?)k){lizvzoJ$S7cO`|M-|n4zpLY2qakuK~ zF2!txv6cGD6T}(^#1f@$()x1esgtNdMJQpY?3bk!{=;%uT?nfKUPT92(NTI0fM}Kx zbc~D`7k2BcHXnQ7fa!nO@yfgXpRlvqWxjaB^Y1*o^Sb@szN$$w4=^}1InrD@qo}_KJEPBA4gtT4m_(?MQ^?qeSS8w_1MwwE$2hq&XHb?-)JlygZlW3-{S@U zp$BNh{!tp8eu6-$B7_A!#pkLCsvCXD!~||bm(<66nBd!(ZiOu$#@J@u;`IG}J#$IB zH~7@9FOjW^GJsDlS08zn?32LIg%T(`H!rzD$CmLUI5o4+M;u7;CkPS;#ESqV_HRk> z%eM)7p?QavY4TPbEZ64o4^YEBarZ{;LA}_8nn+K$dRPcDgNmkgki$>%%Azm3K;r>nzkL1C@VL%zhr(nkMt%>G~!$ z@V#Bb>7HchW6W0OLk|}m1xK;~2%1v1<>*R%nM@;UTjSO&Z16`}gV)==S@0^lg6gV` z>3Qnt%4=B1%tB%M(?9WEa@q_fe|9)Xw_4sWr=0RV{ug6S01a=ka-ZobY~CIK36gA$ACdh?QB^Q`(G(ZyZsO4ibukRQutBG4x)*KzD* zrE94e?y&@ohzNvs@ovQH>QlU4v91hxu#H@U$o*|(zah;WB1QmNq;~NaZsr$o`=y^q zx;{hZMGU5yEwVksvl_=Qia?aenVG*F2onLwsSgA$powwL&EZhu>u+b<#Ms z6}}@L*j7^G^AML}-cLRMgO7pdxm4UtZ3TJ2f*CPRN?0RO9xJd$eaV7O!-p(nZFw#G zfWd}-T@yLb3js12%RGpJyty zH(s|zG0!L__Z(CnOfv)T&lx*6Y`!>0dZT@W{g;NeRt44}6D!jF(!qJ-IIGEE`&aCV z>B1@lD&h;`@Pw1U2#t-UOQDvC)HR|cL_KWC$cp4yKB!?DXLUxSzg|~)k~QjY7H+Ij z8QldJY4E^-8Q$@gH2Kb8kbK+gBwP^MO6X0#EPAxeH~J+hSF`Hh-l0f@;0}~(Ex~z_ z;04afxXOdU*NrZGDBd&$!E1uxTXGmp>Dn}>i%;f{RDcLgH6p#tE{T{hcp|*-h(7*F zMu28lEdEP_Bu+i7@y$|qdgo|dEx6F{mum(d4ur&Zr`VD>Nd4rw8TC_s6@{8p)eiu3wLYU}I8y^?v#P!etd1gOgz zycP5XH^wY3n@z@*@CvJ9smP?_E`N3e_zLFt_+|aLnWrJWQFl^bJR)I(aohmoh<>;} zu=a3lrNMr)Ut4Jrmwr%r1FccHJ_6UlImkbJ4ZKhA%Dq!Y%YEV$!zur9VD0NGqSR%6 zsO63)WH!9=D}-Q$#51_?9aPmZ2rFxndj>bff3>T_W`h#0b4?X^OUq-l0dMY^GH<65 z!eKxaX?cKAmB3NCXG&*3AWQ&}_;t4J>a(K?|5n8Mm!oX7nyhV8rQQ%KQUbjB!2h&0 zvluYp8!?IMHGDTt`JPnDDltmu+F8ZE@ik);5|pbc*^1H$;hh6fNfRck-RF_hVx20N*G@!NXg=9pB)bze2SJ{>? Sk$?FaWt0@v_0(m@j{gHetGd7d diff --git a/crates/nargo_cli/tests/acir_artifacts/brillig_slices/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/brillig_slices/target/acir.gz index a496d8dabe3cf26b7ec87fb8565a7b5628076a2a..e614e42dd45eeffbc41dea9df3db3370c0330c2d 100644 GIT binary patch literal 4878 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 diff --git a/crates/nargo_cli/tests/acir_artifacts/brillig_to_bytes_integration/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/brillig_to_bytes_integration/target/acir.gz index 4584cbdf61cd15df1df37245ba7cd7ba083e173c..48d01aed77396c0e48592ccd51222db3e266f8e1 100644 GIT binary patch literal 407 zcmV;I0cidoiwFP!00000|FxIRP69C$g**ICK?Vhdg-ds?I=FCU(uF>W3Ge>|L<>FP zvyiyp_9mpAncI6#zurlPp>wWrrx^bJ2JSNSJmxXn7JXw^E7bHksN^%nR~~)lPXGSO zIZQB*MxG}2%)%I6yF4FRYV;@HV^iP#-oy78=g?lcH+6rbDXt^tE!O!w*V!h$x#>Pa zNM7zxKSHC${e`V=Pu(W}q@nvm%%72~ywoQLa2g?}1G_`9MmaOgSx0Njxz2HpQO{Y+ z|Ko3hbuo|Owm9;f!)wHK2mKBnysd{ormCxV#6!1653@e^KC8@J{h8i(`j8fT_$7~v zN*q*MQTFQ$UKZf8H1+ZJ&380$X`#CW7v;PbT<%T%oX&~+jnJsw9}nO_AM6k1gvuOJ zjg>ox`hzUwWd$y4Qy;q{mle3Q&|QOza^4FrkEVXYt||5#p;5a(p1^@V*dNOIsLUbN z*tm13KgdE}HsG=~_0jJe)K`B2` literal 427 zcmV;c0aX4UiwFP!00000|HYThPQx$|gdO@9wrubDkwB^~R*Jky);r_bT`3tDV=8m7!OwMN&Q0%qT-{~XRrzwcl02^p@eKAER~vOF zf7?@sF?^qi(>T9oZUnAv^oKbyx&!Y~R^Hv#g7*k@sC%AG%&Aq$y@y|8pN+n18}MdX z&*5C)a*g~R7&V?Zd2u`9R`C*so)6$ZAXagqPj=90h?o}I?UFr;nZjot?M;2vafVgz znalpdZ;X9DuI@71>p25gkNXz*EjZY`92_-OUd@OFZiyadex7|=SabDfn0N9J7JK+H zu1z5wlv|ee>l9oX=rYgBGp8g!|FJBKccc}jFCQK#k)byCc8!soyB*(7{!vhq3A zNAn|$((`kh)TQaEi(+02>kx7*%+WMI)IwYq&}EsG$7Zj~0=m?|T|yVdyd}EaW#!{G zRdQYrjMDva4;{#Z{h^rm!a9T;D|0mU2elBF6?9o=<^8sBZ=KT9J V>kp8L0DV7(vTum^lc+@w003TR&^G`8 diff --git a/crates/nargo_cli/tests/acir_artifacts/brillig_to_le_bytes/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/brillig_to_le_bytes/target/acir.gz index 2c6c56c3c2645551715b485724f45855e804ad05..1f50d47d5f3e12a486e241ab30dc16686055fc36 100644 GIT binary patch literal 924 zcmV;N17rLjiwFP!00000|JB+FPa0tm2H>SA_aP!8A|l?mtcZx`dLRFym;e74*v|K{ zlf1!6+r(+w*<`}94D&v_i{=ZV69hpb7;Q<|$BmCg@niR6TbR(B)lGo09q)gN&t-yY zk}5@&rpi!dsd7|#ssdG!szg<$nxd*uO;c5=W~gdZvs87eIjRQLJXMowfvQEd7-uiR zHTw}iW@8U-DcFycu0u-yK6NL-nguhTPbq#qshJy&&SgUNT*B9E{8CZbnmZ%!7mTo6xhM>lnHjEy1w>4$f~u&!Vp5 zvzyTt9E;%K{5JF~={ml+86Cl~1P;#cK+m$SpH%>85@FQ9UPp$0X>_#4!;K35*(Z0;QTG<*;aLge*Li{IJUvT`8&|FtLyOV zk3GS$3l7fTgPwg|hhKjj2#$SlaQ*@Gbafqm{SgX|E;u+pgq}lPhhKm61jivbIKKxy zN4gHb{^$#iBXDqjA9{{;9e&(Ea2$h!^9Rs#qU-RZhl1k-9GpLdo>N_ik2@0_r{LiH zGw3+tK3d%Yr~MW zX~^0#WNjO=b_`ip3|ZFw+vZ#3|aRKSq}_ZLqpb{A#2}|bzsOkG-N$9WW6wC yy)tCIHe|guWWE2#)+`)*gkzt^%fdA>o!ao7nO&Z;WEdT)3Zqrx* literal 1661 zcmXw&e>~H99LEb;hpb7crY}=2J+x!uQtj)J`Ee)e`e{;Bb0kWIEA2Zpj+GzZ;gKJA zi-+pyGBP2F(8JlpBbJ{2&ae(7- z)I89t5n-FgGTzdApE<_s&|2_XwNJx+;4Q3;>@N%W-R;7yoy#A7dCIir zDI{^`&X%cb5xGyMM#N4FvgVejEp0Dw*_&u)kLMny(2&ljweu0`xscmlj{@CSc8m&V ztAusa^>zH?&6S41S@nMPzeT%>gi#fL9j~Z#3tot>6A5Fa$(5$Tm$EQ9*RN8<4y7e9<-R0B4Gd}v9v5GxUn6Y^$I!)X| zG5oje+Z@rX@6ZwJuoI`RLhoD(9on4db9&^wYtecK5+J&(Mn9B{5G%h1X_^A-d+bjK zypvjtN3KfqIhN+PUTKpQxUn%Yp~Z4Y-uP&LE%sd`(|YHWljTCW(>;T!IaQ)r&xhSP z`ZJ79PU+XEnKlKR9#A#h%CSG)Mz7hC-dvlD)-#c5JE(FclOhH&a1 z)})1acf)o6mb}PpV&H8c85r4M3km6$$h$LVXdbGy`KAK=>xqWkpBBx-B{K0^_50N- zcDI4LcQi%X7l}Zaw)E;a&&g^ce<1a9xszQCIR zBcAe&0u(d~XXm0-$=FUuwibpAVAg;U42d7-UbXeL$FCa_7T#}#$N(lt2lF{|Mr;LO zU;+NkL__g1jDh;Sv5M_~8#xE8-+%uc6^~P>pKW6g7tnTorFm;$E)35AZW;=2Q2eK>UjANERmrRo2f8wdwP zbqDHZl4ltl4D^Duq9~&gFI|=*=Abu#6cPZ}D#x#%bbF3w030HvjN8S_(GlPCgozmB zhsjOy(q_yXTCWOz2}TTUW4#M#F3ZHn+cR-k3kI3+xb67E@G z2M#&_+Z)L*rz4q5X%V`#zg4h3Nb~octRni(f1%|fBRd3qvfOzC5DV3qcv(Z06hhO}(9r|w?<1;?mI`*@R`X&U$N&b0g5fjIz}?szW)ZgpG$)~z+CV)5J_0VYW{dWpu*jOBtpqcKuwvLB1p$$5BC5m84ypn{Ks8o8d~0ZUc${NO=gmWFVFSy>6fbpZRIf_=CGeJOjm zcc~(79-75OqH|FNsL@1c7TlratprsYla6V#EYuIc?suq%jKJ>KYX4;31q3<CEuEi@-ELp} Z@X+Y|xz@#h3i7_LDp1^9uLxMN;y;+8RrUY? diff --git a/crates/nargo_cli/tests/acir_artifacts/double_verify_proof/target/witness.gz b/crates/nargo_cli/tests/acir_artifacts/double_verify_proof/target/witness.gz index 82e8cf3ff57ff728998a3c03148be7a7c94acc09..b250bdfe7bcba64748c742805a950877e2a6b4fe 100644 GIT binary patch delta 8230 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 delta 8043 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 diff --git a/crates/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/acir.gz index b223708aa218844a35ca35a58a69e4a9e32c2e15..01d5c110f72dfcd0b0cbda6666c2c56d2aa384c3 100644 GIT binary patch literal 793 zcmV+!1Lpi6iwFP!00000|J9n=QWIeig%h&x`@WWlh=}}WmduQ(#d}y@2qf?S2sS!u zXhO)+km~|2Cn`I_T%n3@8lA@$3 z8A_ItqvR8P>C`=UC6PUSPe*dWrQi>lN0ktk+ntv)*96$$E?RHtQYMyR7$E z@3TH&eaQNV^)c%c)~8`#K8f)0I(#(yod@p^+sqti?pbr#_-U-*#&?b5-pqXXaDDgA z@@;$WJH8j(1fB`t*mEr0z+QyIjs$1Dk=xO%^S3MKd~tsa5<;`?UyG!mzvIaJ`#l<| z{byO>&PWUTdmCkc&Oc6M_M2svc1Bjv-$_*cSr0go+kKW{J0maX?_C7_%@&V1QP^#k zzhY+;1^t~y&7Z%L6Q%8Ec~9(&vY@~BQS#?K$%)E#v#d2cqblg{EGquIwVbGJKI`_G zolzI`_aO@Yyk|Ml*ld>BU}rQ1{hc4$pV^2Lt>XAeL8@@V6inP2CHY89d^c0(BI{2`!hRnV)S?xcH9|b zL4W2o{oU=%iOIuR_8vQ9D(DZd8*;T^XQNr0)!r4;7*;K;WP{LVP z!dX+oSyjSWQNmeP!dX(nSyaMVP{Ns4!kJUTnN`A>QNo#4!kJRSnH1y1;w3o~Vw@IU XlJiK6)4q)}##QGR2Lh9wEIj}K49KkL literal 3769 zcmYM0dpy)xAIDMdMav*lE+vNK5`%4I+@2ZbHf$FU6M9;cv5Kvx5F={0+$LE>rWrEZ zWw&G!tE^B-7Yz-Sv`O2=Oyv^eQpV^x=lq`8#~g2>o;hVl3Teq+Klw>E`Gx;< zc7FiwRsG@PtigRxgj;m!Q^F@&bdm6h4t+%UM4LV!e4kw}oyx^fy8`ZF;ZJ zO_wecHfYg1g$+9NkHQ9R`d`8ZUAkPjUyD9Dz>D)y@9{VK!c)&9?2mD9uQliP<%kkH zh8lLro?l7hJ!?+d731VyYr*x%5iRQ&;_Q%hTuCc_)|{~G7b8cgfh~6<&vqSdu zN*ecB^X^?Q9o>^HxG6az&yFG9+ii-?rEL9v&7Bq_?6||1`*%fN76!+)zpWBpTNR6o z%MWZCqQv0dHz765 z`Q5Tcy5@IPS-Snymw{5_C!z+OcYMm??U}7X`!f5TGV&^RMrGH|<|w<-3E`=5Q1Cj5}J74*CG7ASH2#2>a|O2PoNxU zw!fy}CZ9q8&yXHCIm@+PwO-9_%=)4z-I&>Sh+vSsKqk+Dmy#u8Dl+-9;<>CtG?Otk znY>H0nhT_B_Vev`wRQlDsM|kzCO5lWMigJsF4MDvIJap8Ca;w8mV_V4d7U|7D>9=q3ZKu7)moHm&$+z`I#|p1R-4=dP=rbqXVrBj$s94sH6hg!lZx^BdlSKI4AZg4J}@-GoujV~V3JR#u~Q zJ~_CxDnrxmSXE}@ds@FlJ3=Ma(o^3c#LmgUJ20(iIP5`L$(8dse~}5JiaAhbJ5XXU zBDbD1jXYaYc8`3vO1I26yJ4d>jgw01oM$jgsbOCWLwl@T6z>O3r5_n}G8Hl9g6nm=Pv^*dOYEJ>qAhr~k+gUPCvV}O!_4~p;n+=2*K>9dd5@STJqeR; zuPK7)tdu^;>~ zV!tZdQDRj2_A)ch&bZ1g%0-W|@FD{zyhw%3xZm}LYI0@~wpZuz$c4>?mzniiU`=KO zV>sb)*wqbStD^9x1mg1)FuJV?M9sZZz(Q=c=;QZ1sz(vROdaHy@-1#qV=jteLsTYTT26Eg>sUv=MG z&1q4E%U(sxdi1A6DEI2olThzDUM)`Yi5eo1kUR~ z2wYcwzooTqC;=yU{}WYS6e>{UnsBBU%zmI9F!yNEnzHgxfB86mnGIP}WlUg?H_Phn zVNNDKc-DL2%#ezyZB&XSn3#aA-wr)6(}EcGK@3vMe*LZg!yvWnNnkkx48A_GM=%V& z7zRQ~r6mDs+LhFf>RYPPYA?COBGQ6$j!{gz$P9K)kF~ z2yZCF5O6=UUWp+9U=RQd$JJ)>AqWF!CBhJ7L%xe)I07+nF$_x~hBXL7A&P^UF2q0} zJYxh1-o$ywM9PSHVwRua&4%;habVe9RW^r!;?Plq;-GF=X_z%5HsXY~0UKr=kh}X1 zFT&M$7NM9CUPH@57tY3Q5LhF;tNJf`v%OHvq^kg47l3!8Pi!%UcO!#OQjI3H~vd z36eg{#7Q(X8Kc!lIW*bE^I~-{G|2+CgC!c;P%#?XTEj}+Y&bMW7~xqjY-ne|(EiLp zbWQ$-LvvJ{eH$Q9+gL#3P)#~BbCr^rfXWHVG2u9B%trYk$sBBuWL7rhGBudB=sYNy z9Fy!jD48je%;`4FTC@g~i~{jCZJV}N;%z$3!bd~A>mK##V0hOdyvtn1uNxq|fe^2E z7{VI?@m|F68X>%^|KGZoPb%(WrE8=%Ugwfu%E20sS34sW4Xp9tD7B0N?=t z81wfz2AC9_F^U03{?ahOHy~g#0{jvKjQkx!fE9J#RhQE6cbKFzV#Tk$QdMvU%d=bb zPM{de?}uc2Ohs~YyN{qFNdI*`5wAGqGEMy9LRuI&FuneTj<#c;U_0omvR!@^XF$&m z{(Cw=>Dj?@7T(LRnK|kFsP7x(nbaA1mbi924Tn4nN1jC>&kCVucadlErO30j$g|TB zgL#=kTZzG(z@yRt1~0wI{fCifq)-&&ir@_XLKx$N2GBDntjvlb20Mg-{4 zDC%@t=X`-OZZr_Lcn~+f#w^Jn#f^u>ZLtlx8^z5lAI7Z=i(4d!+stwlw@MT@FZALN zgz(DhTK~Z-19;T|UP*R~BZgOk;pOFa=OesM2yZEdHyq%-f#EGfc%2YlJJjin{@8Hk zk;wqBPCB5|JAGm!?xEM5PSn1aG-P%UcF#8JK+`5yL(^jI(eV}mO-n?ku@^(rCh_Qa zL#KRg=loG6idule1E7e}oNe+&D543ddA5{y`~9a^5`xOz1D5+d6?-wU1Lgj*8kIX8 zm3t#9_ef*~eLCeIE4VED4S!&T`=dTH%nEm8#l^Oao#$}v>uuQcntBJUCoZL`s{9xG CR$1Wy diff --git a/crates/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/witness.gz b/crates/nargo_cli/tests/acir_artifacts/to_bytes_consistent/target/witness.gz index 34b529f60dca0d5a86ce97982af3f489f6dafccb..a9aad6593523bb3edf3e98020b69cf978fd7bdb7 100644 GIT binary patch literal 268 zcmV+n0rUPJiwFP!00002|E<4h1bUa z00FKZz#Ut2cS0j*uo+5@e9&^iFEL(n<`tz*zS0j*QeIs>h9(7FJvOVGLkt!vP_0j*omx&y6y z?EeyZn6gYN?{n?4ns&vdCI<1LsiH;=G4x$D%hAU=HK~@Q-m;dEESD_(BKip4_yk(d zp!EV;ub}k?TJNCs0a~A+^#xkrp!EY<0$K`M4zvukJZJ^bsz9p-tq58Pw0=SB548S4 Ss|8wZ&>8?tH2L@>5&!@vvVcPX literal 841 zcmV-P1GfAhiwFP!00002|E=3aZ`d#xfZ;JSGc(#roH)adnVAu92!B#o2RUT|r09zGPwM=1KR^%9wG^HmD*Vjr|%D1)DQfU<$+B73= zX~*?lN4UZ=BN;2#j8jswQtEa2I&>}Di(KtUX(*u_M=2}mGaVRV;HoeRl&9Swa)K}n zENOeDqbwl;+m+I{Due%61#DFX&vMm3`|6;54bZD5*s7I|R{Y;YvNmX62ehvXdesA4 z^*MV(fc6r!H$X2FY+0PWsX%)hw0A%+4Ypj)-f95aHw5h)fnJTlRuj%%H3jVxK>KE( zS97q{g0r_@u+@pP*PTK8E}(r^(5oBR>dx7_ zJwW@OpnWgUt2fx{!`XX%LHmB7eSgqv0N5JH+53Y)`@x|75YTHV*z!30zz6LE&^`pc zBCr*6_TezlemH190`wXQwnlOG(P+?q3}`+`nhdt4VD_N|KTR{7*pw~9AwVktf zc7XOfLHk{x*KV-2hqKpvLHm86{eIBv0N6Un*}I28`@^995zy->*gD49d&fch6QKP` z(CZY~I?dVpXF&V2p#3?}>pa-Hz}W{ELHkRf{bkVW3fQ{J*@xFa`|F_n4bbZ**t*5p zN4G)yJD~kt(CZ%9y3g6i50G^w-+vV1VcPdm{@ceWjzky>`3UrS47Q$tt*2n?8Q6Lb zwqAg(mtgA^*m@1N-hi#QVCx;&dJncffUS>U>l4`e47R?2t*>C~8`$~|wtj%EpJ3}3 T*h&OjzrofYWE!iUq(J}x1SzHi diff --git a/crates/nargo_cli/tests/acir_artifacts/to_le_bytes/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/to_le_bytes/target/acir.gz index 608e2b23e8d341f414214575fa1feb59890373a3..cc53ae19c715355f54088dad615e4e19fb750a73 100644 GIT binary patch literal 687 zcmV;g0#N-QiwFP!00000|J9n=a??-{M7{6(zS~6zA%u|IS}ch`D*wR~Ciee-0%K6X zo_Lj~Y~5ScCHG6K=h%`Zm3~Abk*CPt6(dC>|JUp1XMd|sTZqbKsqsqZI4MC&l2W8J zDMQMVa-=+|Kq`_-q%x^Os*-A?I;lZwl3JuTsYB|LdZa#SKpK)pq~*RRKA@=IA?EKh zy3%RYCzww%pJG1Ee1`cf^Eu}8%omt1GGAi8%zTCUD)Tkw>&!QpZ!+IvzRi4x`7ZN4 z=KIVKm>)7fVt&m0#P_Q!?r)#{tvYS39UrEeTGre#<}mS78Q#pbm1WPSE?n5I{bIPL zId?7B@n)W*JXq!&3)?dneppN}>z&+;Y8SttJ?D$%Qiuy>Ex(I|Ait~7^ZOHxQHmK4-&~AU{JBeuB@5a4pEs)P$ela}L}H^0PGICwQNZ zTS0!dCj12NGjS)#Z>kAD!TTiK3-WU`;U{>Vj|V}1t|t5huTud*ex4@$1h2DT3iA7^ z2|vN>1lWT79yQ@7_&*0nkl!~=_z9k;;R*8lt_eTE^9&vZ`8{dEPw+T_;BN+!{9fNl VTzyY56z>B1>o@Zya;;D)005HPS?2%% literal 3594 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 Ss|8wZ&>8?tH2L@>5&!@vvVcPX literal 841 zcmV-P1GfAhiwFP!00002|E=3aZ`d#xfZ;JSGc(#roH)adnVAu92!B#o2RUT|r09zGPwM=1KR^%9wG^HmD*Vjr|%D1)DQfU<$+B73= zX~*?lN4UZ=BN;2#j8jswQtEa2I&>}Di(KtUX(*u_M=2}mGaVRV;HoeRl&9Swa)K}n zENOeDqbwl;+m+I{Due%61#DFX&vMm3`|6;54bZD5*s7I|R{Y;YvNmX62ehvXdesA4 z^*MV(fc6r!H$X2FY+0PWsX%)hw0A%+4Ypj)-f95aHw5h)fnJTlRuj%%H3jVxK>KE( zS97q{g0r_@u+@pP*PTK8E}(r^(5oBR>dx7_ zJwW@OpnWgUt2fx{!`XX%LHmB7eSgqv0N5JH+53Y)`@x|75YTHV*z!30zz6LE&^`pc zBCr*6_TezlemH190`wXQwnlOG(P+?q3}`+`nhdt4VD_N|KTR{7*pw~9AwVktf zc7XOfLHk{x*KV-2hqKpvLHm86{eIBv0N6Un*}I28`@^995zy->*gD49d&fch6QKP` z(CZY~I?dVpXF&V2p#3?}>pa-Hz}W{ELHkRf{bkVW3fQ{J*@xFa`|F_n4bbZ**t*5p zN4G)yJD~kt(CZ%9y3g6i50G^w-+vV1VcPdm{@ceWjzky>`3UrS47Q$tt*2n?8Q6Lb zwqAg(mtgA^*m@1N-hi#QVCx;&dJncffUS>U>l4`e47R?2t*>C~8`$~|wtj%EpJ3}3 T*h&OjzrofYWE!iUq(J}x1SzHi diff --git a/crates/nargo_cli/tests/acir_artifacts/tuples/target/acir.gz b/crates/nargo_cli/tests/acir_artifacts/tuples/target/acir.gz index 8203592cbcec96267d5e492c9f72073ed4443d15..b680ed268d1e650cd42eb73e55ac82d367b40953 100644 GIT binary patch literal 107 zcmb2|=3oGW|63<)`z1 literal 397 zcmV;80doEyiwFP!00000|Ls;$Zi6rkbx5HUx_<7v>Io78CH(CwLxW@QDxD&Q)k;IB zDYn!~^^YMU&o4H1-WveC!>tMLKfG6IrUk+>>fE+d-%Q%*Pt^>g?Nr;1XREF5Z1>ez zV9L+A!eeKsx|9&YjcOh;>-ygghl&8zp8`oEfn7^1#U(50t|DEn3@o zpTTwbEZ+%~Ti06`v`-)}5XJ@ViG3qhaCT^I*?&M>fG#JBVW2A3fhl})9r14;$i2Hl z9)p-!5IgmjEr4zSZh@yEsZ~k|&!nD@Zb+|)ye^33;mrefDXKXjJ=bj^MMICUCMxD)^YK)t%l diff --git a/crates/nargo_cli/tests/acir_artifacts/tuples/target/witness.gz b/crates/nargo_cli/tests/acir_artifacts/tuples/target/witness.gz index 6c8e56d597b8a320505a38942b9c028ccbdfe254..10cffba7141f780b1682ccbe7859f983370670bd 100644 GIT binary patch literal 49 zcmb2|=3oE;rvGbuHgYmBa2(zuewF{ve=XL(3wT+KSPP%rx_?FEN1ROY+{V`nfC>Sh CEfUB8 literal 159 zcmV;Q0AT+giwFP!00002|E-Zp4g)a=1hcR67_hDFM+IU;2&>+?(c!_AA!D}fxec& NUT<-Se0i7y0089^NhkmS diff --git a/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs b/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs index 51592a13ae5..9eda52e0475 100644 --- a/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/crates/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -4,6 +4,8 @@ //! The pass works as follows: //! - Re-insert each instruction in order to apply the instruction simplification performed //! by the [`DataFlowGraph`] automatically as new instructions are pushed. +//! - Check whether any input values have been constrained to be equal to a value of a simpler form +//! by a [constrain instruction][Instruction::Constrain]. If so, replace the input value with the simpler form. //! - Check whether the instruction is [pure][Instruction::is_pure()] //! and there exists a duplicate instruction earlier in the same block. //! If so, the instruction can be replaced with the results of this previous instruction. @@ -28,7 +30,7 @@ use crate::ssa::{ dfg::{DataFlowGraph, InsertInstructionResult}, function::Function, instruction::{Instruction, InstructionId}, - value::ValueId, + value::{Value, ValueId}, }, ssa_gen::Ssa, }; @@ -75,6 +77,7 @@ impl Context { // Cache of instructions without any side-effects along with their outputs. let mut cached_instruction_results: HashMap> = HashMap::default(); + let mut constrained_values: HashMap = HashMap::default(); for instruction_id in instructions { Self::fold_constants_into_instruction( @@ -82,6 +85,7 @@ impl Context { block, instruction_id, &mut cached_instruction_results, + &mut constrained_values, ); } self.block_queue.extend(function.dfg[block].successors()); @@ -92,8 +96,9 @@ impl Context { block: BasicBlockId, id: InstructionId, instruction_result_cache: &mut HashMap>, + constrained_values: &mut HashMap, ) { - let instruction = Self::resolve_instruction(id, dfg); + let instruction = Self::resolve_instruction(id, dfg, constrained_values); let old_results = dfg.instruction_results(id).to_vec(); // If a copy of this instruction exists earlier in the block, then reuse the previous results. @@ -105,20 +110,44 @@ impl Context { // Otherwise, try inserting the instruction again to apply any optimizations using the newly resolved inputs. let new_results = Self::push_instruction(id, instruction.clone(), &old_results, block, dfg); - // If the instruction is pure then we cache the results so we can reuse them if - // the same instruction appears again later in the block. - if instruction.is_pure(dfg) { - instruction_result_cache.insert(instruction, new_results.clone()); - } Self::replace_result_ids(dfg, &old_results, &new_results); + + Self::cache_instruction( + instruction, + new_results, + dfg, + instruction_result_cache, + constrained_values, + ); } /// Fetches an [`Instruction`] by its [`InstructionId`] and fully resolves its inputs. - fn resolve_instruction(instruction_id: InstructionId, dfg: &DataFlowGraph) -> Instruction { + fn resolve_instruction( + instruction_id: InstructionId, + dfg: &DataFlowGraph, + constrained_values: &mut HashMap, + ) -> Instruction { let instruction = dfg[instruction_id].clone(); + // Alternate between resolving `value_id` in the `dfg` and checking to see if the resolved value + // has been constrained to be equal to some simpler value in the current block. + // + // This allows us to reach a stable final `ValueId` for each instruction input as we add more + // constraints to the cache. + fn resolve_cache( + dfg: &DataFlowGraph, + cache: &HashMap, + value_id: ValueId, + ) -> ValueId { + let resolved_id = dfg.resolve(value_id); + match cache.get(&resolved_id) { + Some(cached_value) => resolve_cache(dfg, cache, *cached_value), + None => resolved_id, + } + } + // Resolve any inputs to ensure that we're comparing like-for-like instructions. - instruction.map_values(|value_id| dfg.resolve(value_id)) + instruction.map_values(|value_id| resolve_cache(dfg, constrained_values, value_id)) } /// Pushes a new [`Instruction`] into the [`DataFlowGraph`] which applies any optimizations @@ -151,6 +180,47 @@ impl Context { new_results } + fn cache_instruction( + instruction: Instruction, + instruction_results: Vec, + dfg: &DataFlowGraph, + instruction_result_cache: &mut HashMap>, + constraint_cache: &mut HashMap, + ) { + // If the instruction was a constraint, then create a link between the two `ValueId`s + // to map from the more complex to the simpler value. + if let Instruction::Constrain(lhs, rhs, _) = instruction { + // These `ValueId`s should be fully resolved now. + match (&dfg[lhs], &dfg[rhs]) { + // Ignore trivial constraints + (Value::NumericConstant { .. }, Value::NumericConstant { .. }) => (), + + // Prefer replacing with constants where possible. + (Value::NumericConstant { .. }, _) => { + constraint_cache.insert(rhs, lhs); + } + (_, Value::NumericConstant { .. }) => { + constraint_cache.insert(lhs, rhs); + } + // Otherwise prefer block parameters over instruction results. + // This is as block parameters are more likely to be a single witness rather than a full expression. + (Value::Param { .. }, Value::Instruction { .. }) => { + constraint_cache.insert(rhs, lhs); + } + (Value::Instruction { .. }, Value::Param { .. }) => { + constraint_cache.insert(lhs, rhs); + } + (_, _) => (), + } + } + + // If the instruction doesn't have side-effects, cache the results so we can reuse them if + // the same instruction appears again later in the block. + if instruction.is_pure(dfg) { + instruction_result_cache.insert(instruction, instruction_results); + } + } + /// Replaces a set of [`ValueId`]s inside the [`DataFlowGraph`] with another. fn replace_result_ids( dfg: &mut DataFlowGraph, @@ -321,4 +391,55 @@ mod test { assert_eq!(instruction, &Instruction::Cast(ValueId::test_new(0), Type::unsigned(32))); } + + #[test] + fn constrained_value_replacement() { + // fn main f0 { + // b0(v0: Field): + // constrain v0 == Field 10 + // v1 = add v0, Field 1 + // constrain v1 == Field 11 + // } + // + // After constructing this IR, we run constant folding which should replace references to `v0` + // with the constant `10`. This then allows us to optimize away the rest of the circuit. + + let main_id = Id::test_new(0); + + // Compiling main + let mut builder = FunctionBuilder::new("main".into(), main_id, RuntimeType::Acir); + let v0 = builder.add_parameter(Type::field()); + + let field_10 = builder.field_constant(10u128); + builder.insert_constrain(v0, field_10, None); + + let field_1 = builder.field_constant(1u128); + let v1 = builder.insert_binary(v0, BinaryOp::Add, field_1); + + let field_11 = builder.field_constant(11u128); + builder.insert_constrain(v1, field_11, None); + + let mut ssa = builder.finish(); + let main = ssa.main_mut(); + let instructions = main.dfg[main.entry_block()].instructions(); + assert_eq!(instructions.len(), 3); + + // Expected output: + // + // fn main f0 { + // b0(v0: Field): + // constrain v0 == Field 10 + // } + let ssa = ssa.fold_constants(); + let main = ssa.main(); + let instructions = main.dfg[main.entry_block()].instructions(); + + assert_eq!(instructions.len(), 1); + let instruction = &main.dfg[instructions[0]]; + + assert_eq!( + instruction, + &Instruction::Constrain(ValueId::test_new(0), ValueId::test_new(1), None) + ); + } } From a8d03285e0c54fae525b3019dd7cc4807c6437c8 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 5 Sep 2023 21:24:44 +0100 Subject: [PATCH 9/9] fix(aztec): fix compilation of `aztec_library.rs` (#2567) --- crates/noirc_frontend/src/hir/def_map/aztec_library.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/noirc_frontend/src/hir/def_map/aztec_library.rs b/crates/noirc_frontend/src/hir/def_map/aztec_library.rs index f357ba5b740..efd947a6c04 100644 --- a/crates/noirc_frontend/src/hir/def_map/aztec_library.rs +++ b/crates/noirc_frontend/src/hir/def_map/aztec_library.rs @@ -506,7 +506,7 @@ pub(crate) fn create_return_type(ty: &str) -> FunctionReturnType { let return_path = chained_path!("aztec", "abi", ty); let ty = make_type(UnresolvedTypeData::Named(return_path, vec![])); - FunctionReturnType::Ty(ty, Span::default()) + FunctionReturnType::Ty(ty) } /// Create Context Finish