-
Notifications
You must be signed in to change notification settings - Fork 219
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add assert_constant * Remove println & dbg * Add test
- Loading branch information
Showing
12 changed files
with
134 additions
and
6 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
crates/nargo_cli/tests/compile_failure/assert_constant_fail/Nargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[package] | ||
name = "assert_constant_fail" | ||
type = "bin" | ||
authors = [""] | ||
compiler_version = "0.9.0" | ||
|
||
[dependencies] |
10 changes: 10 additions & 0 deletions
10
crates/nargo_cli/tests/compile_failure/assert_constant_fail/src/main.nr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
use dep::std::assert_constant; | ||
|
||
fn main(x: Field) { | ||
foo(5, x); | ||
} | ||
|
||
fn foo(constant: Field, non_constant: Field) { | ||
assert_constant(constant); | ||
assert_constant(non_constant); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
use crate::{ | ||
errors::RuntimeError, | ||
ssa::{ | ||
ir::{ | ||
function::Function, | ||
instruction::{Instruction, InstructionId, Intrinsic}, | ||
value::ValueId, | ||
}, | ||
ssa_gen::Ssa, | ||
}, | ||
}; | ||
|
||
impl Ssa { | ||
/// A simple SSA pass to go through each instruction and evaluate each call | ||
/// to `assert_constant`, issuing an error if any arguments to the function are | ||
/// not constants. | ||
/// | ||
/// Note that this pass must be placed directly before loop unrolling to be | ||
/// useful. Any optimization passes between this and loop unrolling will cause | ||
/// the constants that this pass sees to be potentially different than the constants | ||
/// seen by loop unrolling. Furthermore, this pass cannot be a part of loop unrolling | ||
/// since we must go through every instruction to find all references to `assert_constant` | ||
/// while loop unrolling only touches blocks with loops in them. | ||
pub(crate) fn evaluate_assert_constant(mut self) -> Result<Ssa, RuntimeError> { | ||
for function in self.functions.values_mut() { | ||
for block in function.reachable_blocks() { | ||
// Unfortunately we can't just use instructions.retain(...) here since | ||
// check_instruction can also return an error | ||
let instructions = function.dfg[block].take_instructions(); | ||
let mut filtered_instructions = Vec::with_capacity(instructions.len()); | ||
|
||
for instruction in instructions { | ||
if check_instruction(function, instruction)? { | ||
filtered_instructions.push(instruction); | ||
} | ||
} | ||
|
||
*function.dfg[block].instructions_mut() = filtered_instructions; | ||
} | ||
} | ||
Ok(self) | ||
} | ||
} | ||
|
||
/// During the loop unrolling pass we also evaluate calls to `assert_constant`. | ||
/// This is done in this pass because loop unrolling is the only pass that will error | ||
/// if a value (the loop bounds) are not known constants. | ||
/// | ||
/// This returns Ok(true) if the given instruction should be kept in the block and | ||
/// Ok(false) if it should be removed. | ||
fn check_instruction( | ||
function: &mut Function, | ||
instruction: InstructionId, | ||
) -> Result<bool, RuntimeError> { | ||
let assert_constant_id = function.dfg.import_intrinsic(Intrinsic::AssertConstant); | ||
match &function.dfg[instruction] { | ||
Instruction::Call { func, arguments } => { | ||
if *func == assert_constant_id { | ||
evaluate_assert_constant(function, instruction, arguments) | ||
} else { | ||
Ok(true) | ||
} | ||
} | ||
_ => Ok(true), | ||
} | ||
} | ||
|
||
/// Evaluate a call to `assert_constant`, returning an error if any of the elements are not | ||
/// constants. If all of the elements are constants, Ok(false) is returned. This signifies a | ||
/// success but also that the instruction need not be reinserted into the block being unrolled | ||
/// since it has already been evaluated. | ||
fn evaluate_assert_constant( | ||
function: &Function, | ||
instruction: InstructionId, | ||
arguments: &[ValueId], | ||
) -> Result<bool, RuntimeError> { | ||
if arguments.iter().all(|arg| function.dfg.is_constant(*arg)) { | ||
Ok(false) | ||
} else { | ||
let location = function.dfg.get_location(&instruction); | ||
Err(RuntimeError::AssertConstantFailed { location }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters