Skip to content
13 changes: 13 additions & 0 deletions compiler/noirc_evaluator/src/ssa/opt/pure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,23 @@ impl Ssa {
function.dfg.set_function_purities(purities.clone());
}

debug_assert!(purity_analysis_post_check(&self));
Comment thread
TomAFrench marked this conversation as resolved.
Outdated

self
}
}

/// Post-check condition for [Function::remove_bit_shifts].
Comment thread
TomAFrench marked this conversation as resolved.
Outdated
///
/// Returns `true` if:
/// - all functions have a purity status attached to it.
///
/// Otherwise returns `false`.
fn purity_analysis_post_check(ssa: &Ssa) -> bool {
// TODO: We have N different copies of the purity hashmap (one per function), ideally this would be deduplicated.
Comment thread
TomAFrench marked this conversation as resolved.
Outdated
ssa.functions.iter().all(|(id, function)| function.dfg.purity_of(*id).is_some())
}

pub(crate) type FunctionPurities = HashMap<FunctionId, Purity>;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
Expand Down
31 changes: 31 additions & 0 deletions compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ impl Function {

context.replace_value(old_result, new_result);
});

debug_assert!(remove_bit_shifts_post_check(self));
Comment thread
TomAFrench marked this conversation as resolved.
Outdated
}
}

Expand Down Expand Up @@ -343,6 +345,35 @@ impl Context<'_, '_, '_> {
}
}

/// Post-check condition for [Function::remove_bit_shifts].
///
/// Returns `true` if:
/// - `func` is not an ACIR function, OR
/// - `func` does not contain any bitshift instructions.
///
/// Otherwise returns `false`.
fn remove_bit_shifts_post_check(func: &Function) -> bool {
// Non-ACIR functions should be unaffected.
if !func.runtime().is_acir() {
return true;
}

// Otherwise there should be no shift-left or shift-right instructions in any reachable block.
for block_id in func.reachable_blocks() {
let instruction_ids = func.dfg[block_id].instructions();
for instruction_id in instruction_ids {
if matches!(
func.dfg[*instruction_id],
Instruction::Binary(Binary { operator: BinaryOp::Shl | BinaryOp::Shr, .. })
) {
return false;
}
}
}

true
}

#[cfg(test)]
mod tests {
use crate::{assert_ssa_snapshot, ssa::ssa_gen::Ssa};
Expand Down
27 changes: 27 additions & 0 deletions compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl Function {
} else {
Context::default().remove_if_else(self);
}
debug_assert!(remove_if_else_post_check(self));
}
}

Expand Down Expand Up @@ -224,6 +225,32 @@ fn slice_capacity_change(
}
}

/// Post-check condition for [Function::remove_if_else].
///
/// Returns `true` if:
/// - `func` is a Brillig function, OR
/// - `func` does not contain any if-else instructions.
///
/// Otherwise returns `false`.
fn remove_if_else_post_check(func: &Function) -> bool {
// Brillig functions should be unaffected.
if func.runtime().is_brillig() {
return true;
}

// Otherwise there should be no shift-left or shift-right instructions in any reachable block.
Comment thread
TomAFrench marked this conversation as resolved.
Outdated
for block_id in func.reachable_blocks() {
let instruction_ids = func.dfg[block_id].instructions();
for instruction_id in instruction_ids {
if matches!(func.dfg[*instruction_id], Instruction::IfElse { .. }) {
return false;
}
}
}

true
}

#[cfg(test)]
mod tests {
use crate::{assert_ssa_snapshot, ssa::ssa_gen::Ssa};
Expand Down