Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
15 changes: 10 additions & 5 deletions compiler/noirc_evaluator/src/ssa/interpreter/intrinsics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::io::Write;
use std::{hash::BuildHasher, io::Write};

use acvm::{AcirField, BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement};
use bn254_blackbox_solver::derive_generators;
Expand Down Expand Up @@ -831,11 +831,16 @@ fn values_to_fields(values: &[Value]) -> Vec<FieldElement> {
// but that's catered for the by the SSA generation: the env is passed as separate values.
fields.push(FieldElement::from(id.to_u32()));
}
Value::Intrinsic(x) => {
panic!("didn't expect to print intrinsics: {x}")
}
Value::ForeignFunction(x) => {
panic!("didn't expect to print foreign functions: {x}")
// The actual display of functions only shows the type, but expects the ID.
// Send a hash so we can interpret the Initial SSA until we wrap these values with a normal function.
let hash = rustc_hash::FxBuildHasher.hash_one(x);
fields.push(FieldElement::from(hash));
}
Value::Intrinsic(x) => {
// Same as foreign functions: just pass something so we can handle the initial SSA even if somehow an intrinsic makes it here.
let hash = rustc_hash::FxBuildHasher.hash_one(x);
fields.push(FieldElement::from(hash));
}
}
// Chamber the length for a potential vector following it.
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/ssa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ pub fn create_program_with_minimal_passes(
for func in &program.functions {
assert!(
func.unconstrained,
"The minimum SSA pipeline only works with Brillig: '{}' needs to be unconstrained",
"The minimal SSA pipeline only works with Brillig: '{}' needs to be unconstrained",
func.name
);
}
Expand Down
42 changes: 33 additions & 9 deletions compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use rustc_hash::FxHashMap as HashMap;
/// fn apply(function_id: Field, arg1: Field, arg2: Field) -> Field {
/// match function_id {
/// 0 -> function0(arg1, arg2),
/// 1 -> function0(arg1, arg2),
/// 1 -> function1(arg1, arg2),
/// ...
/// N -> functionN(arg1, arg2),
/// }
Expand All @@ -75,7 +75,7 @@ struct ApplyFunction {
}

/// All functions used as a value that share the same signature and runtime type
/// Maps ([Signature], [RuntimeType]) -> Vec<[FunctionId]>
/// Maps ([Signature], Caller [RuntimeType]) -> Vec<([FunctionId], Callee [RuntimeType])>
type Variants = BTreeMap<(Signature, RuntimeType), Vec<(FunctionId, RuntimeType)>>;
/// All generated apply functions for each grouping of function variants.
/// Each apply function is handles a specific ([Signature], [RuntimeType]) group.
Expand All @@ -94,6 +94,10 @@ impl Ssa {
/// See [`defunctionalize`][self] module for more information.
#[tracing::instrument(level = "trace", skip(self))]
pub(crate) fn defunctionalize(mut self) -> Ssa {
// Check that we have removed all cases we don't handle in this pass.
#[cfg(debug_assertions)]
self.functions.values().for_each(defunctionalize_pre_check);

// Find all functions used as value that share the same signature and runtime type
let variants = find_variants(&self);

Expand Down Expand Up @@ -360,10 +364,19 @@ fn find_variants(ssa: &Ssa) -> Variants {
fn find_functions_as_values(func: &Function) -> BTreeSet<FunctionId> {
let mut functions_as_values: BTreeSet<FunctionId> = BTreeSet::new();

let mut process_value = |value_id: ValueId| {
if let Value::Function(id) = func.dfg[value_id] {
functions_as_values.insert(id);
visit_values_other_than_call_target(func, |value| {
if let Value::Function(id) = value {
functions_as_values.insert(*id);
}
});

functions_as_values
}

/// Visit all values which are *not* targets of a `Call`.
fn visit_values_other_than_call_target(func: &Function, mut f: impl FnMut(&Value)) {
let mut process_value = |value_id: ValueId| {
f(&func.dfg[value_id]);
};

for block_id in func.reachable_blocks() {
Expand All @@ -382,8 +395,6 @@ fn find_functions_as_values(func: &Function) -> BTreeSet<FunctionId> {

block.unwrap_terminator().for_each_value(&mut process_value);
}

functions_as_values
}

/// Finds all dynamic dispatch signatures in the given function.
Expand Down Expand Up @@ -546,7 +557,7 @@ fn create_apply_function(
caller_runtime: RuntimeType,
function_ids: Vec<(FunctionId, RuntimeType)>,
) -> FunctionId {
assert!(
debug_assert!(
function_ids.len() > 1,
"create_apply_function is expected to be called with two or more FunctionIds"
);
Expand Down Expand Up @@ -754,6 +765,19 @@ fn make_dummy_return_data(function_builder: &mut FunctionBuilder, typ: &Type) ->
}
}

/// Check pre-execution properties.
///
/// Panics if:
/// * Any intrinsic or foreign function is passed as a value.
#[cfg(debug_assertions)]
fn defunctionalize_pre_check(function: &Function) {
visit_values_other_than_call_target(function, |value| match value {
Value::ForeignFunction(name) => panic!("foreign function as value: {name}"),
Value::Intrinsic(intrinsic) => panic!("intrinsic function as value: {intrinsic}"),
_ => (),
});
}

/// Check post-execution properties:
/// * All blocks which took function parameters should receive a discriminator instead
#[cfg(debug_assertions)]
Expand Down Expand Up @@ -1096,7 +1120,7 @@ mod tests {
acir(inline) fn main f0 {
b0():
call f1()
return f1
return f1
}
acir(inline) fn bar f1 {
b0():
Expand Down
1 change: 1 addition & 0 deletions compiler/noirc_frontend/src/monomorphization/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ pub enum Type {
Tuple(Vec<Type>),
Slice(Box<Type>),
Reference(Box<Type>, /*mutable:*/ bool),
/// `(args, ret, env, unconstrained)`
Function(
/*args:*/ Vec<Type>,
/*ret:*/ Box<Type>,
Expand Down
16 changes: 12 additions & 4 deletions compiler/noirc_frontend/src/monomorphization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ mod debug;
pub mod debug_types;
pub mod errors;
pub mod printer;
pub mod proxies;
pub mod tests;
pub mod visitor;

struct LambdaContext {
env_ident: ast::Ident,
Expand All @@ -60,7 +62,7 @@ struct LambdaContext {
///
/// This struct holds the FIFO queue of functions to monomorphize, which is added to
/// whenever a new (function, type) combination is encountered.
pub(super) struct Monomorphizer<'interner> {
pub struct Monomorphizer<'interner> {
/// Functions are keyed by their unique ID, whether they're unconstrained, their expected type,
/// and any generics they have so that we can monomorphize a new version of the function for each type.
///
Expand Down Expand Up @@ -203,8 +205,11 @@ pub fn monomorphize_debug(
debug_variables,
debug_functions,
debug_types,
);
Ok(program.handle_ownership())
)
.handle_ownership()
.create_foreign_proxies();
Comment thread
jfecher marked this conversation as resolved.

Ok(program)
}

impl<'interner> Monomorphizer<'interner> {
Expand Down Expand Up @@ -1282,7 +1287,10 @@ impl<'interner> Monomorphizer<'interner> {
}

/// Convert a non-tuple/struct type to a monomorphized type
fn convert_type(typ: &HirType, location: Location) -> Result<ast::Type, MonomorphizationError> {
pub fn convert_type(
typ: &HirType,
location: Location,
) -> Result<ast::Type, MonomorphizationError> {
Self::convert_type_helper(typ, location, &mut HashSet::default())
}

Expand Down
Loading
Loading