diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert/Prover.toml new file mode 100644 index 00000000000..4dd6b405159 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert/Prover.toml @@ -0,0 +1 @@ +x = "1" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert/src/main.nr new file mode 100644 index 00000000000..320369c7b67 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert/src/main.nr @@ -0,0 +1,11 @@ +// Tests a very simple program. +// +// The features being tested is using assert on brillig +fn main(x: Field) { + assert(1 == conditional(x as bool)); +} + +unconstrained fn conditional(x : bool) -> Field { + assert(x); + 1 +} \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert_fail/Nargo.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert_fail/Nargo.toml new file mode 100644 index 00000000000..e0b467ce5da --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert_fail/Nargo.toml @@ -0,0 +1,5 @@ +[package] +authors = [""] +compiler_version = "0.1" + +[dependencies] \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert_fail/Prover.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert_fail/Prover.toml new file mode 100644 index 00000000000..11497a473bc --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert_fail/Prover.toml @@ -0,0 +1 @@ +x = "0" diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert_fail/src/main.nr b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert_fail/src/main.nr new file mode 100644 index 00000000000..320369c7b67 --- /dev/null +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/brillig_assert_fail/src/main.nr @@ -0,0 +1,11 @@ +// Tests a very simple program. +// +// The features being tested is using assert on brillig +fn main(x: Field) { + assert(1 == conditional(x as bool)); +} + +unconstrained fn conditional(x : bool) -> Field { + assert(x); + 1 +} \ No newline at end of file diff --git a/crates/nargo_cli/tests/test_data_ssa_refactor/config.toml b/crates/nargo_cli/tests/test_data_ssa_refactor/config.toml index b3700b5690d..66525b5048d 100644 --- a/crates/nargo_cli/tests/test_data_ssa_refactor/config.toml +++ b/crates/nargo_cli/tests/test_data_ssa_refactor/config.toml @@ -2,4 +2,4 @@ exclude = [] # List of tests (as their directory name) expecting to fail: if the test pass, we report an error. -fail = [""] +fail = ["brillig_assert_fail"] diff --git a/crates/noirc_evaluator/src/brillig/artifact.rs b/crates/noirc_evaluator/src/brillig/artifact.rs index c3129f0390e..56eaa653460 100644 --- a/crates/noirc_evaluator/src/brillig/artifact.rs +++ b/crates/noirc_evaluator/src/brillig/artifact.rs @@ -17,12 +17,32 @@ pub(crate) struct BrilligArtifact { pub(crate) byte_code: Vec, /// The set of jumps that need to have their locations /// resolved. - unresolved_jumps: Vec<(JumpLabel, BasicBlockId)>, + unresolved_jumps: Vec<(JumpLabel, UnresolvedJumpLocation)>, /// A map of the basic blocks to their positions /// in the bytecode. blocks: HashMap, } +/// When constructing the bytecode, there may be instructions +/// which require one to jump to a specific `Block` +/// or a position relative to the current instruction. +/// +/// The position of a `Block` cannot always be known +/// at this point in time, so Jumps are unresolved +/// until all blocks have been processed in the `Block` +/// variant of this enum. +/// +/// Sometimes the relative position of an Jump +/// may be known, from the Jump label, but since +/// the absolute position of a Jump label is not known until +/// after we have linked the bytecode to other functions. +/// We add relative jumps into the `Relative` variant of this enum. +#[derive(Debug, Clone, Copy)] +pub(crate) enum UnresolvedJumpLocation { + Block(BasicBlockId), + Relative(i32), +} + impl BrilligArtifact { /// Link some compiled brillig bytecode with its referenced artifacts. pub(crate) fn link(&mut self, obj: &BrilligArtifact) -> Vec { @@ -46,7 +66,7 @@ impl BrilligArtifact { } /// Adds a unresolved jump to be fixed at the end of bytecode processing. - pub(crate) fn add_unresolved_jump(&mut self, destination: BasicBlockId) { + pub(crate) fn add_unresolved_jump(&mut self, destination: UnresolvedJumpLocation) { self.unresolved_jumps.push((self.code_len(), destination)); } @@ -65,10 +85,15 @@ impl BrilligArtifact { /// /// Note: This should only be called once all blocks are processed. fn resolve_jumps(&mut self) { - for (jump_label, block) in &self.unresolved_jumps { + for (jump_label, unresolved_location) in &self.unresolved_jumps { let jump_instruction = self.byte_code[*jump_label].clone(); - let actual_block_location = self.blocks[block]; + let actual_block_location = match unresolved_location { + UnresolvedJumpLocation::Block(b) => self.blocks[b], + UnresolvedJumpLocation::Relative(location) => { + (location + *jump_label as i32) as usize + } + }; match jump_instruction { BrilligOpcode::Jump { location } => { @@ -84,7 +109,7 @@ impl BrilligArtifact { BrilligOpcode::JumpIfNot { condition, location: actual_block_location }; } BrilligOpcode::JumpIf { condition, location } => { - assert_eq!(location, 0,"location is not zero, which means that the jump label does not need resolving"); + assert_eq!(location, 0, "location is not zero, which means that the jump label does not need resolving"); self.byte_code[*jump_label] = BrilligOpcode::JumpIf { condition, location: actual_block_location }; diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen.rs b/crates/noirc_evaluator/src/brillig/brillig_gen.rs index 30ff53e1452..ce162df90b5 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen.rs @@ -1,5 +1,5 @@ use super::{ - artifact::BrilligArtifact, + artifact::{BrilligArtifact, UnresolvedJumpLocation}, binary::{type_of_binary_operation, BrilligBinaryOp}, memory::BrilligMemory, }; @@ -103,13 +103,13 @@ impl BrilligGen { /// Adds a unresolved `Jump` instruction to the bytecode. fn jump(&mut self, target: BasicBlockId) { - self.obj.add_unresolved_jump(target); + self.obj.add_unresolved_jump(UnresolvedJumpLocation::Block(target)); self.push_code(BrilligOpcode::Jump { location: 0 }); } /// Adds a unresolved `JumpIf` instruction to the bytecode. fn jump_if(&mut self, condition: RegisterIndex, target: BasicBlockId) { - self.obj.add_unresolved_jump(target); + self.obj.add_unresolved_jump(UnresolvedJumpLocation::Block(target)); self.push_code(BrilligOpcode::JumpIf { condition, location: 0 }); } @@ -162,6 +162,13 @@ impl BrilligGen { let result_register = self.get_or_create_register(result_ids[0]); self.convert_ssa_binary(binary, dfg, result_register); } + Instruction::Constrain(value) => { + let condition = self.convert_ssa_value(*value, dfg); + // jump to the relative location after the trap + self.obj.add_unresolved_jump(UnresolvedJumpLocation::Relative(2)); + self.push_code(BrilligOpcode::JumpIf { condition, location: 0 }); + self.push_code(BrilligOpcode::Trap); + } Instruction::Allocate => { let pointer_register = self.get_or_create_register(dfg.instruction_results(instruction_id)[0]);