From fe7bb99045abdd3052614f3a25a5ad7be3bd62a3 Mon Sep 17 00:00:00 2001 From: ludamad Date: Thu, 22 Jun 2023 16:43:46 -0400 Subject: [PATCH] feat(brillig): foreign calls with dynamic-size objects (#1705) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * disable mac tests * feat: added support for modulo ops on brillig (#1621) * feat: added support for modulo ops * chore: use ACVM 0.14.3 * revert change as its unrelated * small comment refactor --------- Co-authored-by: kevaundray * feat(brillig): foreign call/oracle compilation (#1600) * remove mac runner * chore: generate brillig opcode for simple identity unconstrained function (#1536) * feat(brillig): added arithmetic operations on brillig (#1565) Co-authored-by: kevaundray * make ranges be polymorphic integers * chore(brillig): Clean up handling of Binary operations (#1571) * chore(ssa refactor): Rename Brillig example (#1563) * chore(brillig): added tests for all field binary operations (#1586) * chore(brillig): added tests for brillig integer operations (#1590) * feat: process blocks and jumps when compiling brillig (#1591) * process jumps between blocks * fix jumps * add doc comments * cargo fmt * code refactor * update code comment --------- Co-authored-by: kevaundray * feat: process blocks and jumps when compiling brillig (#1591) * process jumps between blocks * fix jumps * add doc comments * cargo fmt * code refactor * update code comment --------- Co-authored-by: kevaundray * feat(brillig): start of oracles/foreign calls * fix: broken tests * feat(brillig): parsing oracles/foreign calls (#1596) * feat(brillig): start of oracles/foreign calls * fix: broken tests * Update execute.rs * feat: more foreign call work * self.data -> self.vars * chore(brillig): Add handling of the not instruction (#1609) * test: brillig oracle * Reinstate option * make behavior consistent * remove closure * change index_type * Update crates/noirc_frontend/src/hir/type_check/expr.rs * feat(brillig): loops (#1610) * make ranges be polymorphic integers * feat: brillig loop support * fix: fixed brillig returns and stop * fix: do not apply constants folding to brillig fns * chore: update acvm pointer, cleanup * style: newline on cargo toml * make behavior consistent * remove closure * change index_type * Update crates/noirc_frontend/src/hir/type_check/expr.rs * better debug information for unsupported instruction * remove edge case for optimizations * clippy fix * patch infinite loop --------- Co-authored-by: kevaundray Co-authored-by: jfecher * feat: Foreign calls compiling and basic print executed in nargo (#1612) * get foreign calls compiling and basic print executed in nargo * cargo clipy and cargo fmt * missing * Update crates/noirc_evaluator/src/brillig/brillig_gen.rs * add issue num for logging --------- Co-authored-by: kevaundray * chore: resolve immutable array merge differences (#1617) * chore(ssa refactor): Switch to immutable arrays (#1578) * Represent SSA arrays with im::Vector * Get tests passing * Implement assign with immutable arrays * Add constant folding pass * Update comments * Clippy * Update comment * Update type of array * Update crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * Undo formatting changes in instruction.rs * Massive acir_gen update * Refactor acir array operations into a shared function * Appease clippy * Update to_radix and to_bits in acir_gen to return arrays * Disable assert * Fix convert_type for arrays * Include AcirType in AcirValue::Var variant * Fix black box functions * Appease clippy * Fix simple_radix * Add doc comments --------- Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * feat: Make for-loop range be a polymorphic integer instead of just Field in unconstrained functions (#1583) * make ranges be polymorphic integers * make behavior consistent * remove closure * change index_type * Update crates/noirc_frontend/src/hir/type_check/expr.rs --------- Co-authored-by: jfecher * chore(ssa refactor): fix brillig post master merge * chore(ssa refactor): accidental merge undelete --------- Co-authored-by: jfecher Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> Co-authored-by: kevaundray * chore(ssa refactor): Add more documentation for truncation (#1607) * add more documentation * small change * Update crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs * Update .github/workflows/test.yml * Update .github/workflows/test.yml * remove dbg * change printer for foreign call * Update crates/noirc_evaluator/src/ssa_refactor/ir/function.rs * Update crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs Co-authored-by: kevaundray * Update crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs --------- Co-authored-by: kevaundray Co-authored-by: guipublic <47281315+guipublic@users.noreply.github.com> Co-authored-by: Álvaro Rodríguez Co-authored-by: jfecher Co-authored-by: Maxim Vezenov Co-authored-by: joss-aztec <94053499+joss-aztec@users.noreply.github.com> Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * feat: add support for assert in brillig (#1603) * remove mac runner * chore: generate brillig opcode for simple identity unconstrained function (#1536) * feat(brillig): added arithmetic operations on brillig (#1565) Co-authored-by: kevaundray * make ranges be polymorphic integers * chore(brillig): Clean up handling of Binary operations (#1571) * chore(ssa refactor): Rename Brillig example (#1563) * chore(brillig): added tests for all field binary operations (#1586) * chore(brillig): added tests for brillig integer operations (#1590) * feat: process blocks and jumps when compiling brillig (#1591) * process jumps between blocks * fix jumps * add doc comments * cargo fmt * code refactor * update code comment --------- Co-authored-by: kevaundray * feat: process blocks and jumps when compiling brillig (#1591) * process jumps between blocks * fix jumps * add doc comments * cargo fmt * code refactor * update code comment --------- Co-authored-by: kevaundray * feat(brillig): parsing oracles/foreign calls (#1596) * feat(brillig): start of oracles/foreign calls * fix: broken tests * Update execute.rs * support assert in brillig * self.data -> self.vars * Avoid not in the test * chore(brillig): Add handling of the not instruction (#1609) * make behavior consistent * remove closure * change index_type * Update crates/noirc_frontend/src/hir/type_check/expr.rs * feat(brillig): loops (#1610) * make ranges be polymorphic integers * feat: brillig loop support * fix: fixed brillig returns and stop * fix: do not apply constants folding to brillig fns * chore: update acvm pointer, cleanup * style: newline on cargo toml * make behavior consistent * remove closure * change index_type * Update crates/noirc_frontend/src/hir/type_check/expr.rs * better debug information for unsupported instruction * remove edge case for optimizations * clippy fix * patch infinite loop --------- Co-authored-by: kevaundray Co-authored-by: jfecher * chore: resolve immutable array merge differences (#1617) * chore(ssa refactor): Switch to immutable arrays (#1578) * Represent SSA arrays with im::Vector * Get tests passing * Implement assign with immutable arrays * Add constant folding pass * Update comments * Clippy * Update comment * Update type of array * Update crates/noirc_evaluator/src/ssa_refactor/ir/instruction.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * Undo formatting changes in instruction.rs * Massive acir_gen update * Refactor acir array operations into a shared function * Appease clippy * Update to_radix and to_bits in acir_gen to return arrays * Disable assert * Fix convert_type for arrays * Include AcirType in AcirValue::Var variant * Fix black box functions * Appease clippy * Fix simple_radix * Add doc comments --------- Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * feat: Make for-loop range be a polymorphic integer instead of just Field in unconstrained functions (#1583) * make ranges be polymorphic integers * make behavior consistent * remove closure * change index_type * Update crates/noirc_frontend/src/hir/type_check/expr.rs --------- Co-authored-by: jfecher * chore(ssa refactor): fix brillig post master merge * chore(ssa refactor): accidental merge undelete --------- Co-authored-by: jfecher Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> Co-authored-by: kevaundray * chore(ssa refactor): Add more documentation for truncation (#1607) * add more documentation * small change * Update crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs * Update .github/workflows/test.yml * Update .github/workflows/test.yml * Remove optimisation for handling assert * add the assert jump to the list of jumps to fix * add doc comment --------- Co-authored-by: kevaundray Co-authored-by: Álvaro Rodríguez Co-authored-by: ludamad Co-authored-by: jfecher Co-authored-by: joss-aztec <94053499+joss-aztec@users.noreply.github.com> Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * chore(ssa refactor): Separate Brillig only logic from Brillig-SSA generation logic (#1631) * separate brillig only logic from logic that combines both brillig and ssa * move operations related to brillig-ssa conversion to brillig_gen * intermediate step -- make build work by leaking the abstraction * refactor return instruction -- all of the implementation details about brillig are no longer in brillig_gen * fix clippy * add TODO * move `convert_integer_mod` into BrilligIr * encapsulate modulo operation in brillig_gen * process binary instruction * refactor const instruction * make code surrounding jumps satisfy the abstraction * move not instruction * add foreign call instruction * move load and store instructions to brillig_ir * move truncate instruction * move `mov`, `stop` and `allocate_array` methods * fix clippy * remove push_code method in brillig_gen * move jump and jmpif instructions to brillig_ir * clean up terminator instruction * remove allow(deprecated) lint * refactor document for link and link_with * use .into so we can get rid of Value import * add docs * Update crates/noirc_evaluator/src/brillig/brillig_ir/artifact.rs Co-authored-by: Álvaro Rodríguez * Update crates/noirc_evaluator/src/brillig/brillig_gen.rs * make code a bit clearer * fix clippy --------- Co-authored-by: Álvaro Rodríguez * chore(ssa_refactor): Improve foreign call compilation (#1644) * remove ForeignCall instruction from SSA * remove unnecessary Oracle RuntimeType * remove old comment * feat: Brillig array inputs and outputs (#1630) * first attempt at brillig multiple array inptus * working array identity function for brillig * cleanup dbgs * remove unused imports * remove dbg * a little cleanup * fix up foreign calls for array inputs and outputs * fix outputs clippy err * move conversion to RegisterValueOrArray to its own method * missing &mut and TODO link * PR comment for brillig output array types * cleanup comment * enable struct inputs/outputs * cargo clippy * *WIP* call brillig function from brillig * chore(brillig): master into brillig main (#1663) * fix(ssa refactor): resolve replaced value ids for printing (#1535) * fix(ssa refactor): resolve replaced value ids for printing * fix(ssa refactor): Expand PR #1535 to resolve ValueIds in all SSA passes (#1642) * Expand PR * chore(ssa refactor): more value id resolving * chore(ssa refactor): another value id resolve --------- Co-authored-by: Joss --------- Co-authored-by: jfecher * chore(ssa refactor): enable_side_effects instruction (#1547) * chore(ssa refactor): enable_side_effects instruction * chore(ssa refactor): fix and document enable_side_effects insertions * chore(ssa refactor): rm comments * fix(ssa refactor): redundant EnableSideEffects * chore(ssa refactor): cp working tests (#1619) * chore(ssa gen): ssa gen truncate instruction * chore(ssa refactor): max bit size for subtract * Update crates/noirc_evaluator/src/ssa_refactor/ssa_gen/context.rs Co-authored-by: jfecher * chore(ssa refactor): truncate shift left * chore(ssa refactor): Add integer modulus when truncating subtraction * chore(ssa refactor): clippy * chore(ssa refactor): fix left shift max bit size * chore(ssa refactor): cp xor test * chore(ssa refactor): cp working tests * chore(ssa refactor): more working tests * chore(ssa refactor): cp working test --------- Co-authored-by: kevaundray Co-authored-by: jfecher * chore(ssa refactor): Remove unit values from SSA IR (#1646) * Remove unit values * Fix test * Fix comment * chore: Upgrade codespan dependencies (#1647) * chore(ssa refactor): Implement dead instruction elimination pass (#1595) * Add dead instruction elimination pass * Enable the pass * chore(ssa refactor): simple mut test * chore(ssa refactor): fixup and add doc comments * chore(ssa refactor): post merge fix --------- Co-authored-by: Joss * chore(brillig): Update acvm dependency (#1653) chore: update acvm dep * refactor: remove unused assign --------- Co-authored-by: joss-aztec <94053499+joss-aztec@users.noreply.github.com> Co-authored-by: jfecher Co-authored-by: kevaundray Co-authored-by: Blaine Bublitz Co-authored-by: Joss * discriminate labels per function * initial changes to get noir building using adam/foreign-call-vectors acvm branch * include fix for array output from foreign calls * fixed commit to reference remote patch * small cleanup * do not save the special registers * cargo clippy * towards dynamic arrays * chore: bump acvm for better acvm vectors * Towards brillig vectors * push fix for test_brillig_ir_foreign_call_return_vector * fix pseudo-noir in test * add Trap opcode to make Brillig IR test more accurate * move code from Adams and Guillaume's branch for BrilligIR Co-authored-by: guipublic <47281315+guipublic@users.noreply.github.com> Co-authored-by: ludamad * add used registers method Co-authored-by: ludamad * add method to handle calling normal functions and thread the function_id_to_block_id through necessary functions * add unresolved_call method into artifact struct * remove Vec::clone * small clean-up: - remove magic constant - use mov_instruction method * modify API for linking * pass parameter length and return type length to BrilligContext * move entry_point_instruction to artifact for now * refactor API -- still has a lot of scaffolding * remove pretty_print_opcode * chore: high level brillig printorrr * chore: move acvm * feat: implement call semantics (#1746) * fix: entry point and exit point handling * feat: function linking * docs: added comments * docs: more comments * fix: correct_usize_op * fix: fix moving registers to registers * fix: fixed array handling across calls * docs: improved error msgs * Update * post-merge fixes * Post-merge brillig ir printer fixes * fix: post-merge build * chore: fixing diff. TODO not building * Working build * Foreign call test * chore: fix deps --------- Co-authored-by: kevaundray Co-authored-by: Álvaro Rodríguez Co-authored-by: guipublic <47281315+guipublic@users.noreply.github.com> Co-authored-by: jfecher Co-authored-by: Maxim Vezenov Co-authored-by: joss-aztec <94053499+joss-aztec@users.noreply.github.com> Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> Co-authored-by: guipublic Co-authored-by: Blaine Bublitz Co-authored-by: Joss --- crates/nargo/src/ops/execute.rs | 6 +- .../brillig_oracle/src/main.nr | 1 - .../noirc_evaluator/src/brillig/brillig_ir.rs | 87 ++++++++++++++++++- .../src/brillig/brillig_ir/debug_show.rs | 21 ++--- 4 files changed, 99 insertions(+), 16 deletions(-) diff --git a/crates/nargo/src/ops/execute.rs b/crates/nargo/src/ops/execute.rs index ec3cd9bd7c6..c83d57beb4f 100644 --- a/crates/nargo/src/ops/execute.rs +++ b/crates/nargo/src/ops/execute.rs @@ -31,9 +31,9 @@ pub fn execute_circuit( // Execute foreign calls // TODO(#1615): "oracle_print_impl" and "oracle_print_array_impl" are just identity funcs if foreign_call_wait_info.function == "oracle_print_impl" { - let value = foreign_call_wait_info.inputs[0][0]; - println!("{:?}", value.to_field().to_hex()); - brillig.foreign_call_results.push(value.into()); + let values = &foreign_call_wait_info.inputs[0]; + println!("{:?}", values[0].to_field().to_hex()); + brillig.foreign_call_results.push(foreign_call_wait_info.inputs[0][0].into()); } else if foreign_call_wait_info.function == "oracle_print_array_impl" { let mut outputs_hex = Vec::new(); for values in foreign_call_wait_info.inputs.clone() { diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_oracle/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_oracle/src/main.nr index d3dad57456f..3f4f718b81d 100644 --- a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_oracle/src/main.nr +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_oracle/src/main.nr @@ -21,4 +21,3 @@ unconstrained fn oracle_print_array_wrapper(arr: [Field; 2]) { oracle_print_array(arr); } - diff --git a/crates/noirc_evaluator/src/brillig/brillig_ir.rs b/crates/noirc_evaluator/src/brillig/brillig_ir.rs index 2d28a27f69b..439bf7220c2 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_ir.rs @@ -338,7 +338,6 @@ impl BrilligContext { /// the VM. pub(crate) fn return_instruction(&mut self, return_registers: &[RegisterIndex]) { debug_show::return_instruction(return_registers); - let mut sources = Vec::with_capacity(return_registers.len()); let mut destinations = Vec::with_capacity(return_registers.len()); @@ -452,7 +451,6 @@ impl BrilligContext { outputs: &[RegisterOrMemory], ) { debug_show::foreign_call_instruction(func_name.clone(), inputs, outputs); - // TODO(https://github.com/noir-lang/acvm/issues/366): Enable multiple inputs and outputs to a foreign call let opcode = BrilligOpcode::ForeignCall { function: func_name, destinations: outputs.to_vec(), @@ -598,7 +596,9 @@ impl BrilligContext { } /// Adds a unresolved external `Call` instruction to the bytecode. + /// This calls into another function compiled into this brillig artifact. pub(crate) fn add_external_call_instruction(&mut self, func_label: T) { + debug_show::add_external_call_instruction(func_label.to_string()); self.obj.add_unresolved_external_call( BrilligOpcode::Call { location: 0 }, func_label.to_string(), @@ -708,3 +708,86 @@ pub(crate) enum BrilligBinaryOp { // Brillig. Modulo { is_signed_integer: bool, bit_size: u32 }, } + +#[cfg(test)] +mod tests { + use std::vec; + + use acvm::acir::brillig_vm::{ + BinaryIntOp, ForeignCallOutput, ForeignCallResult, RegisterIndex, RegisterOrMemory, + Registers, VMStatus, Value, VM, + }; + + use crate::brillig::brillig_ir::{BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE}; + + use super::{BrilligBinaryOp, BrilligOpcode, ReservedRegisters}; + + /// Test a Brillig foreign call returning a vector + #[test] + fn test_brillig_ir_foreign_call_return_vector() { + // pseudo-noir: + // + // #[oracle(make_number_sequence)] + // unconstrained fn make_number_sequence(size: u32) -> Vec { + // } + // + // unconstrained fn main() -> Vec { + // let the_sequence = make_number_sequence(12); + // assert(the_sequence.len() == 12); + // } + let mut context = BrilligContext::new(vec![], vec![]); + let r_stack = ReservedRegisters::stack_pointer(); + // Start stack pointer at 0 + context.const_instruction(r_stack, Value::from(0_usize)); + let r_input_size = RegisterIndex::from(ReservedRegisters::len()); + let r_array_ptr = RegisterIndex::from(ReservedRegisters::len() + 1); + let r_output_size = RegisterIndex::from(ReservedRegisters::len() + 2); + let r_equality = RegisterIndex::from(ReservedRegisters::len() + 3); + context.const_instruction(r_input_size, Value::from(12_usize)); + // copy our stack frame to r_array_ptr + context.mov_instruction(r_array_ptr, r_stack); + context.foreign_call_instruction( + "make_number_sequence".into(), + &[RegisterOrMemory::RegisterIndex(r_input_size)], + &[RegisterOrMemory::HeapVector(r_stack, r_output_size)], + ); + // push stack frame by r_returned_size + context.binary_instruction( + r_stack, + r_output_size, + r_stack, + BrilligBinaryOp::Integer { + op: BinaryIntOp::Add, + bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + }, + ); + // check r_input_size == r_output_size + context.binary_instruction( + r_input_size, + r_output_size, + r_equality, + BrilligBinaryOp::Integer { + op: BinaryIntOp::Equals, + bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + }, + ); + // We push a JumpIf and Trap opcode directly as the constrain instruction + // uses unresolved jumps which requires a block to be constructed in SSA and + // we don't need this for Brillig IR tests + context.push_opcode(BrilligOpcode::JumpIf { condition: r_equality, location: 8 }); + context.push_opcode(BrilligOpcode::Trap); + + context.stop_instruction(); + + let bytecode = context.artifact().byte_code; + let number_sequence: Vec = (0_usize..12_usize).map(Value::from).collect(); + let mut vm = VM::new( + Registers { inner: vec![] }, + vec![], + bytecode, + vec![ForeignCallResult { values: vec![ForeignCallOutput::Array(number_sequence)] }], + ); + let status = vm.process_opcodes(); + assert_eq!(status, VMStatus::Finished); + } +} diff --git a/crates/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/crates/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 457de2264d3..d67e8d7b714 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -103,12 +103,8 @@ impl DebugToString for RegisterOrMemory { RegisterOrMemory::HeapArray(index, size) => { format!("{}[0..{}]", index.debug_to_string(), size) } - RegisterOrMemory::HeapVector(location_index, length_index) => { - format!( - "{}[0..{}]", - location_index.debug_to_string(), - length_index.debug_to_string() - ) + RegisterOrMemory::HeapVector(index, size_register) => { + format!("{}[0..*{}]", index.debug_to_string(), size_register.debug_to_string()) } } } @@ -121,14 +117,14 @@ impl DebugToString for [T] { } macro_rules! debug_println { - ( $first:expr ) => { + ( $literal:expr ) => { if ENABLE_DEBUG_TRACE { - println!("{}", $first); + println!("{}", $literal); } }; - ( $first:expr, $( $x:expr ),* ) => { + ( $format_message:expr, $( $x:expr ),* ) => { if ENABLE_DEBUG_TRACE { - println!($first, $( $x.debug_to_string(), )*) + println!($format_message, $( $x.debug_to_string(), )*) } }; } @@ -257,3 +253,8 @@ pub(crate) fn cast_instruction( ) { debug_println!(" CAST {} FROM {} TO {} BITS", destination, source, target_bit_size); } + +/// Debug function for cast_instruction +pub(crate) fn add_external_call_instruction(func_label: String) { + debug_println!(" CALL {}", func_label); +}