Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ssa): Turn the Brillig constraints check back on by default #7404

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions compiler/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,25 +136,21 @@
#[arg(long)]
pub skip_underconstrained_check: bool,

/// Flag to turn on the compiler check for missing Brillig call constraints.
/// Warning: This can degrade compilation speed but will also find some correctness errors.
/// Flag to turn off the compiler check for missing Brillig call constraints.
/// Warning: This can improve compilation speed but can also lead to correctness errors.
/// This check should always be run on production code.
#[arg(long)]
pub enable_brillig_constraints_check: bool,
pub skip_brillig_constraints_check: bool,

/// Flag to turn on extra Brillig bytecode to be generated to guard against invalid states in testing.
#[arg(long, hide = true)]
pub enable_brillig_debug_assertions: bool,

/// Hidden Brillig call check flag to maintain CI compatibility (currently ignored)
#[arg(long, hide = true)]
pub skip_brillig_constraints_check: bool,

/// Flag to turn on the lookback feature of the Brillig call constraints

Check warning on line 149 in compiler/noirc_driver/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)
/// check, allowing tracking argument values before the call happens preventing
/// certain rare false positives (leads to a slowdown on large rollout functions)
#[arg(long)]
pub enable_brillig_constraints_check_lookback: bool,

Check warning on line 153 in compiler/noirc_driver/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)

/// Setting to decide on an inlining strategy for Brillig functions.
/// A more aggressive inliner should generate larger programs but more optimized
Expand Down Expand Up @@ -697,9 +693,9 @@
},
emit_ssa: if options.emit_ssa { Some(context.package_build_path.clone()) } else { None },
skip_underconstrained_check: options.skip_underconstrained_check,
enable_brillig_constraints_check_lookback: options

Check warning on line 696 in compiler/noirc_driver/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)
.enable_brillig_constraints_check_lookback,

Check warning on line 697 in compiler/noirc_driver/src/lib.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)
enable_brillig_constraints_check: options.enable_brillig_constraints_check,
skip_brillig_constraints_check: options.skip_brillig_constraints_check,
inliner_aggressiveness: options.inliner_aggressiveness,
max_bytecode_increase_percent: options.max_bytecode_increase_percent,
};
Expand Down
6 changes: 3 additions & 3 deletions compiler/noirc_evaluator/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,13 @@
/// Skip the check for under constrained values
pub skip_underconstrained_check: bool,

/// Enable the missing Brillig call constraints check
pub enable_brillig_constraints_check: bool,
/// Skip the missing Brillig call constraints check
pub skip_brillig_constraints_check: bool,

/// Enable the lookback feature of the Brillig call constraints

Check warning on line 78 in compiler/noirc_evaluator/src/ssa.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)
/// check (prevents some rare false positives, leads to a slowdown
/// on large rollout functions)
pub enable_brillig_constraints_check_lookback: bool,

Check warning on line 81 in compiler/noirc_evaluator/src/ssa.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)

/// The higher the value, the more inlined Brillig functions will be.
pub inliner_aggressiveness: i64,
Expand Down Expand Up @@ -143,13 +143,13 @@
));
}

if options.enable_brillig_constraints_check {
if !options.skip_brillig_constraints_check {
ssa_level_warnings.extend(time(
"After Check for Missing Brillig Call Constraints",
options.print_codegen_timings,
|| {
ssa.check_for_missing_brillig_constraints(
options.enable_brillig_constraints_check_lookback,

Check warning on line 152 in compiler/noirc_evaluator/src/ssa.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)
)
},
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
/// and return a vector of bug reports if any have been found
pub(crate) fn check_for_missing_brillig_constraints(
&mut self,
enable_lookback: bool,

Check warning on line 44 in compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)
) -> Vec<SsaReport> {
// Skip the check if there are no Brillig functions involved
if !self.functions.values().any(|func| func.runtime().is_brillig()) {
Expand All @@ -57,7 +57,7 @@
match function_to_process.runtime() {
RuntimeType::Acir { .. } => {
let mut context =
DependencyContext { enable_lookback, ..Default::default() };

Check warning on line 60 in compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)
context.build(function_to_process, &self.functions);
context.collect_warnings(function_to_process)
}
Expand Down Expand Up @@ -110,12 +110,12 @@
side_effects_condition: Option<ValueId>,
// Map of Brillig call ids to sets of the value ids descending
// from their arguments and results
tainted: BTreeMap<InstructionId, BrilligTaintedIds>,
tainted: BTreeMap<(FunctionId, InstructionId), BrilligTaintedIds>,
// Map of argument value ids to the Brillig call ids employing them
call_arguments: HashMap<ValueId, Vec<InstructionId>>,
// Maintains count of calls being tracked
tracking_count: usize,
// The set of calls currently being tracked
tracking: HashSet<(FunctionId, InstructionId)>,
// Opt-in to use the lookback feature (tracking the argument values

Check warning on line 118 in compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (lookback)
// of a Brillig call before the call happens if their usage precedes
// it). Can prevent certain false positives, at the cost of
// slowing down checking large functions considerably
Expand All @@ -138,8 +138,6 @@
array_elements: HashMap<ValueId, Vec<usize>>,
// Initial result value ids, along with element ids for arrays
root_results: HashSet<ValueId>,
// The flag signaling that the call should be now tracked
tracking: bool,
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -195,7 +193,6 @@
results: results_status,
array_elements,
root_results: HashSet::from_iter(results.iter().copied()),
tracking: false,
}
}

Expand Down Expand Up @@ -358,7 +355,7 @@

if !wrapped_call_found {
// Record the current call, remember the argument values involved
self.tainted.insert(*instruction, current_tainted);
self.tainted.insert((function.id(), *instruction), current_tainted);
arguments.iter().for_each(|value| {
self.call_arguments
.entry(*value)
Expand Down Expand Up @@ -394,23 +391,19 @@
for argument in &arguments {
if let Some(calls) = self.call_arguments.get(argument) {
for call in calls {
if let Some(tainted_ids) = self.tainted.get_mut(call) {
tainted_ids.tracking = true;
self.tracking_count += 1;
if self.tainted.get(&(function.id(), *call)).is_some() {
self.tracking.insert((function.id(), *call));
}
}
}
}
}
if let Some(tainted_ids) = self.tainted.get_mut(instruction) {
if !tainted_ids.tracking {
tainted_ids.tracking = true;
self.tracking_count += 1;
}
if self.tainted.get(&(function.id(), *instruction)).is_some() {
self.tracking.insert((function.id(), *instruction));
}

// We can skip over instructions while nothing is being tracked
if self.tracking_count > 0 {
if !self.tracking.is_empty() {
let mut results = Vec::new();

// Collect non-constant instruction results
Expand Down Expand Up @@ -519,7 +512,7 @@
// results involving the array in question, to properly
// populate the array element tainted sets
Instruction::ArrayGet { array, index } => {
self.process_array_get(function, *array, *index, &results);
self.process_array_get(*array, *index, &results, function);
// Record all the used arguments as parents of the results
self.update_children(&arguments, &results);
}
Expand Down Expand Up @@ -557,8 +550,12 @@
let warnings: Vec<SsaReport> = self
.tainted
.keys()
.map(|brillig_call| {
trace!("tainted structure for {}: {:?}", brillig_call, self.tainted[brillig_call]);
.map(|(_, brillig_call)| {
trace!(
"tainted structure for {:?}: {:?}",
brillig_call,
self.tainted[&(function.id(), *brillig_call)]
);
SsaReport::Bug(InternalBug::UncheckedBrilligCall {
call_stack: function.dfg.get_instruction_call_stack(*brillig_call),
})
Expand All @@ -582,8 +579,8 @@
self.side_effects_condition.map(|v| parents.insert(v));

// Don't update sets for the calls not yet being tracked
for (_, tainted_ids) in self.tainted.iter_mut() {
if tainted_ids.tracking {
for (call, tainted_ids) in self.tainted.iter_mut() {
if self.tracking.contains(call) {
tainted_ids.update_children(&parents, children);
}
}
Expand All @@ -600,15 +597,15 @@
.collect();

// Skip untracked calls
for (_, tainted_ids) in self.tainted.iter_mut() {
if tainted_ids.tracking {
for (call, tainted_ids) in self.tainted.iter_mut() {
if self.tracking.contains(call) {
tainted_ids.store_partial_constraints(&constrained_values);
}
}

self.tainted.retain(|_, tainted_ids| {
self.tainted.retain(|call, tainted_ids| {
if tainted_ids.check_constrained() {
self.tracking_count -= 1;
self.tracking.remove(call);
false
} else {
true
Expand All @@ -619,19 +616,19 @@
/// Process ArrayGet instruction for tracked Brillig calls
fn process_array_get(
&mut self,
function: &Function,
array: ValueId,
index: ValueId,
element_results: &[ValueId],
function: &Function,
) {
use acvm::acir::AcirField;

// Only allow numeric constant indices
if let Some(value) = function.dfg.get_numeric_constant(index) {
if let Some(index) = value.try_to_u32() {
// Skip untracked calls
for (_, tainted_ids) in self.tainted.iter_mut() {
if tainted_ids.tracking {
for (call, tainted_ids) in self.tainted.iter_mut() {
if self.tracking.contains(call) {
tainted_ids.process_array_get(array, index as usize, element_results);
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/ssa/opt/hint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ mod tests {
emit_ssa: None,
skip_underconstrained_check: true,
enable_brillig_constraints_check_lookback: false,
enable_brillig_constraints_check: false,
skip_brillig_constraints_check: true,
inliner_aggressiveness: 0,
max_bytecode_increase_percent: None,
};
Expand Down
2 changes: 0 additions & 2 deletions tooling/nargo_cli/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,6 @@ fn generate_compile_success_no_bug_tests(test_file: &mut File, test_data_dir: &P
&test_dir,
"compile",
r#"
nargo.arg("--enable-brillig-constraints-check");
nargo.assert().success().stderr(predicate::str::contains("bug:").not());
"#,
&MatrixConfig::default(),
Expand Down Expand Up @@ -463,7 +462,6 @@ fn generate_compile_success_with_bug_tests(test_file: &mut File, test_data_dir:
&test_dir,
"compile",
r#"
nargo.arg("--enable-brillig-constraints-check");
nargo.assert().success().stderr(predicate::str::contains("bug:"));
"#,
&MatrixConfig::default(),
Expand Down
Loading