Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
10e8c60
Add ownership pass skeleton; parameter rcs
jfecher Mar 27, 2025
693674a
Prepend new clones to the function body
jfecher Mar 27, 2025
ed76a41
Add explicit ownership pass
Mar 28, 2025
4fd9e0c
Clippy
Mar 28, 2025
2143ea3
Add comment
Mar 28, 2025
2eb526b
Remove commented code
Mar 28, 2025
b1fbf5b
Document & fix bug I found
Mar 28, 2025
a7a0f00
Clippy & comment
Mar 28, 2025
8b2c389
Replicate dropping logic too
Mar 28, 2025
c5466ce
Fix pass by mut value; update rc tests
Mar 28, 2025
ebcecb9
Fix rc underflow check
Mar 28, 2025
4a80918
Fix underflow check
Mar 28, 2025
c499ef7
Add check in inc_rc
Mar 28, 2025
83208dc
fmt
Mar 28, 2025
dcce9b4
fmt tests
Mar 28, 2025
4e1b223
Merge branch 'master' into jf/fix-underflow-check
jfecher Mar 31, 2025
f880354
Bump eddsa timeout 1s
jfecher Mar 31, 2025
6d4e8b0
Add experimental switch for ownership pass
jfecher Mar 31, 2025
81d2f2c
Update compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs
Mar 31, 2025
11a9ec5
Apply suggestions from code review
Mar 31, 2025
c1d060d
Add mutable flag to monomorphized reference type
jfecher Mar 31, 2025
11ed7ce
Merge branch 'jf/ownership' of https://github.com/noir-lang/noir into…
jfecher Mar 31, 2025
e2cab43
Revert brillig change
jfecher Mar 31, 2025
a9fe0bb
Revert extra newline
jfecher Mar 31, 2025
a06718d
Merge branch 'jf/fix-underflow-check' into jf/ownership
jfecher Mar 31, 2025
b28e132
Update tests
jfecher Apr 1, 2025
a131fa5
Patch correctness issue & port ssa change from other PR
jfecher Apr 1, 2025
d406647
Add test regression
jfecher Apr 1, 2025
93f2ad4
Update compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs
Apr 1, 2025
9d8f20a
Update compiler/noirc_frontend/src/ownership/mod.rs
Apr 1, 2025
1445731
Change function name
jfecher Apr 1, 2025
748b39f
The debugger seems to fail on tests with references
jfecher Apr 1, 2025
4f4d603
Merge branch 'jf/ownership' into jf/ownership-experimental
jfecher Apr 1, 2025
9c4662d
Merge branch 'jf/ownership-experimental' of https://github.com/noir-l…
jfecher Apr 1, 2025
ff740ef
Clone identifiers
jfecher Apr 1, 2025
e92dbc6
Clone on dereferences as well; add regression test
jfecher Apr 1, 2025
bc281d7
Merge branch 'master' into jf/ownership-experimental
jfecher Apr 1, 2025
3ff2189
fmt
jfecher Apr 1, 2025
375d33a
fmt test
jfecher Apr 1, 2025
1d51578
Clean up output some
jfecher Apr 2, 2025
6394b4b
Add skeleton of move analysis pass
jfecher Apr 2, 2025
5705da3
Rework to identify last use & move variable
jfecher Apr 3, 2025
55686d8
Only clone individual fields on field access
jfecher Apr 3, 2025
0c9f17a
Ellide cloning in more cases
jfecher Apr 3, 2025
bf8fb5e
Debug & find new bug in master
jfecher Apr 3, 2025
9eb8567
Merge branch 'master' into jf/ownership-experimental
jfecher Apr 4, 2025
7b8c132
Print 'unconstrained' in monomorphization printer
jfecher Apr 4, 2025
f25e92b
Delay dereferences
jfecher Apr 4, 2025
01fb965
Treat Dereference rhs' as reference expressions
jfecher Apr 4, 2025
e0d22bc
Fix merge
jfecher Apr 4, 2025
b5ddef4
Clippy
jfecher Apr 4, 2025
9634edd
Remove -Zownership flag from execute tests
jfecher Apr 4, 2025
5129d20
Exclude test
jfecher Apr 4, 2025
2c9b930
Fmt
jfecher Apr 4, 2025
0edd6cb
Move failing test
jfecher Apr 7, 2025
6162719
Just remove the test
jfecher Apr 7, 2025
c27bf5e
Documentation!
jfecher Apr 7, 2025
bcb2549
Fix odd brillig bit size error
jfecher Apr 8, 2025
3daedfd
Comment out slice push back rc check
jfecher Apr 8, 2025
8010d43
Add issue number
jfecher Apr 8, 2025
01ac506
Merge branch 'master' into jf/ownership-experimental
jfecher Apr 9, 2025
3012838
Fix ast fuzzer
jfecher Apr 9, 2025
d4e3a81
Merge branch 'master' into jf/ownership-experimental
jfecher Apr 9, 2025
2ee57b0
Add comments from PR review
jfecher Apr 14, 2025
534d3ed
More merge conflicts from the ast fuzzer
jfecher Apr 14, 2025
b9e13b3
More ast fuzzer changes
jfecher Apr 14, 2025
d10ebf7
Remove vector pop front branch
jfecher Apr 14, 2025
8d69ac8
Update compiler/noirc_frontend/src/ownership/mod.rs
jfecher Apr 14, 2025
654a9d1
Update compiler/noirc_frontend/src/ownership/mod.rs
jfecher Apr 14, 2025
e998b6e
Update compiler/noirc_frontend/src/ownership/mod.rs
jfecher Apr 14, 2025
41edfc0
Update compiler/noirc_frontend/src/ownership/mod.rs
jfecher Apr 14, 2025
a235bf1
Update compiler/noirc_frontend/src/ownership/last_uses.rs
jfecher Apr 14, 2025
78508b2
Format
jfecher Apr 14, 2025
fb6e5e8
Edit test
jfecher Apr 14, 2025
54d43b8
Remove unused imports
jfecher Apr 14, 2025
517f825
More test edits
jfecher Apr 14, 2025
3b0ab3a
Snap updates
jfecher Apr 15, 2025
b6a92d7
Merge branch 'master' into jf/ownership-experimental
jfecher Apr 15, 2025
f290b16
Remove smoke test from test_programs
jfecher Apr 15, 2025
ae2f593
Fix ssa tests which use monomorphization
jfecher Apr 15, 2025
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
9 changes: 8 additions & 1 deletion compiler/noirc_driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,16 +687,23 @@ pub fn compile_no_check(
force_compile: bool,
) -> Result<CompiledProgram, CompileError> {
let force_unconstrained = options.force_brillig;
let experimental_ownership = options.unstable_features.contains(&UnstableFeature::Ownership);

let program = if options.instrument_debug {
monomorphize_debug(
main_function,
&mut context.def_interner,
&context.debug_instrumenter,
force_unconstrained,
experimental_ownership,
)?
} else {
monomorphize(main_function, &mut context.def_interner, force_unconstrained)?
monomorphize(
main_function,
&mut context.def_interner,
force_unconstrained,
experimental_ownership,
)?
};

if options.show_monomorphized {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,60 +68,27 @@ pub(super) fn compile_vector_pop_front_procedure<F: AcirField + DebugToString>(
BrilligBinaryOp::Sub,
);

let is_rc_one = brillig_context.allocate_register();
brillig_context.codegen_usize_op(
source_rc.address,
is_rc_one,
BrilligBinaryOp::Equals,
1_usize,
// FIXME: https://github.com/noir-lang/noir/issues/7976
// There used to be a branch here for `if is_rc_one` but it was removed due to issues with
// mutating the reference count while popping from the front of the vector.
brillig_context.codegen_initialize_vector(target_vector, target_size, None);

let target_vector_items_pointer =
brillig_context.codegen_make_vector_items_pointer(target_vector);

let source_copy_pointer = brillig_context.allocate_register();
brillig_context.memory_op_instruction(
source_items_pointer.address,
item_pop_count_arg,
source_copy_pointer,
BrilligBinaryOp::Add,
);
// Now we copy the source vector starting at index removed_items.len() into the target vector
brillig_context.codegen_mem_copy(source_copy_pointer, target_vector_items_pointer, target_size);

brillig_context.deallocate_register(source_copy_pointer);
brillig_context.deallocate_register(target_vector_items_pointer);

brillig_context.codegen_branch(is_rc_one, |brillig_context, is_rc_one| {
if is_rc_one {
// We reuse the source vector, moving the metadata to the right (decreasing capacity)
brillig_context.memory_op_instruction(
source_vector.pointer,
item_pop_count_arg,
target_vector.pointer,
BrilligBinaryOp::Add,
);
brillig_context.memory_op_instruction(
source_capacity.address,
item_pop_count_arg,
source_capacity.address,
BrilligBinaryOp::Sub,
);
brillig_context.codegen_initialize_vector_metadata(
target_vector,
target_size,
Some(source_capacity),
);
} else {
brillig_context.codegen_initialize_vector(target_vector, target_size, None);

let target_vector_items_pointer =
brillig_context.codegen_make_vector_items_pointer(target_vector);

let source_copy_pointer = brillig_context.allocate_register();
brillig_context.memory_op_instruction(
source_items_pointer.address,
item_pop_count_arg,
source_copy_pointer,
BrilligBinaryOp::Add,
);
// Now we copy the source vector starting at index removed_items.len() into the target vector
brillig_context.codegen_mem_copy(
source_copy_pointer,
target_vector_items_pointer,
target_size,
);

brillig_context.deallocate_register(source_copy_pointer);
brillig_context.deallocate_register(target_vector_items_pointer);
}
});

brillig_context.deallocate_register(is_rc_one);
brillig_context.deallocate_single_addr(target_size);
brillig_context.deallocate_single_addr(source_rc);
brillig_context.deallocate_single_addr(source_size);
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_evaluator/src/ssa/ssa_gen/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use noirc_frontend::function_path;
use noirc_frontend::test_utils::{Expect, get_monomorphized};

fn get_initial_ssa(src: &str, test_path: &str) -> Result<Ssa, RuntimeError> {
let program = match get_monomorphized(src, test_path, Expect::Success) {
let program = match get_monomorphized(src, Some(test_path), Expect::Success) {
Ok(program) => program,
Err(errors) => {
panic!(
Expand Down
7 changes: 7 additions & 0 deletions compiler/noirc_frontend/src/monomorphization/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ pub struct GlobalId(pub u32);
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct FuncId(pub u32);

/// Each identifier is given a unique ID to distinguish different uses of identifiers.
/// This is used, for example, in last use analysis to determine which identifiers represent
/// the last use of their definition and can thus be moved instead of cloned.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct IdentId(pub u32);

impl Display for FuncId {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
Expand All @@ -101,6 +107,7 @@ pub struct Ident {
pub mutable: bool,
pub name: String,
pub typ: Type,
pub id: IdentId,
}

#[derive(Debug, Clone, Hash)]
Expand Down
58 changes: 49 additions & 9 deletions compiler/noirc_frontend/src/monomorphization/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::{
node_interner::{self, DefinitionKind, NodeInterner, StmtId, TraitImplKind, TraitMethodId},
};
use acvm::{FieldElement, acir::AcirField};
use ast::{GlobalId, While};
use ast::{GlobalId, IdentId, While};
use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet};
use iter_extended::{btree_map, try_vecmap, vecmap};
use noirc_errors::Location;
Expand Down Expand Up @@ -61,7 +61,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.
struct Monomorphizer<'interner> {
pub(super) 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 @@ -103,6 +103,7 @@ struct Monomorphizer<'interner> {
next_local_id: u32,
next_global_id: u32,
next_function_id: u32,
next_ident_id: u32,

is_range_loop: bool,

Expand Down Expand Up @@ -137,15 +138,23 @@ pub fn monomorphize(
main: node_interner::FuncId,
interner: &mut NodeInterner,
force_unconstrained: bool,
enable_ownership: bool,
) -> Result<Program, MonomorphizationError> {
monomorphize_debug(main, interner, &DebugInstrumenter::default(), force_unconstrained)
monomorphize_debug(
main,
interner,
&DebugInstrumenter::default(),
force_unconstrained,
enable_ownership,
)
}

pub fn monomorphize_debug(
main: node_interner::FuncId,
interner: &mut NodeInterner,
debug_instrumenter: &DebugInstrumenter,
force_unconstrained: bool,
experimental_ownership: bool,
) -> Result<Program, MonomorphizationError> {
let debug_type_tracker = DebugTypeTracker::build_from_debug_instrumenter(debug_instrumenter);
let mut monomorphizer = Monomorphizer::new(interner, debug_type_tracker);
Expand Down Expand Up @@ -202,7 +211,11 @@ pub fn monomorphize_debug(
debug_functions,
debug_types,
);
Ok(program.handle_ownership(monomorphizer.next_local_id))
Ok(program.handle_ownership(
monomorphizer.next_local_id,
monomorphizer.next_ident_id,
experimental_ownership,
))
}

impl<'interner> Monomorphizer<'interner> {
Expand All @@ -217,6 +230,7 @@ impl<'interner> Monomorphizer<'interner> {
next_local_id: 0,
next_global_id: 0,
next_function_id: 0,
next_ident_id: 0,
interner,
lambda_envs_stack: Vec::new(),
is_range_loop: false,
Expand All @@ -226,7 +240,7 @@ impl<'interner> Monomorphizer<'interner> {
}
}

fn next_local_id(&mut self) -> LocalId {
pub(super) fn next_local_id(&mut self) -> LocalId {
let id = self.next_local_id;
self.next_local_id += 1;
LocalId(id)
Expand All @@ -244,6 +258,12 @@ impl<'interner> Monomorphizer<'interner> {
GlobalId(id)
}

pub(super) fn next_ident_id(&mut self) -> IdentId {
let id = self.next_ident_id;
self.next_ident_id += 1;
IdentId(id)
}

fn lookup_local(&mut self, id: node_interner::DefinitionId) -> Option<Definition> {
self.locals.get(&id).copied().map(Definition::Local)
}
Expand Down Expand Up @@ -776,7 +796,14 @@ impl<'interner> Monomorphizer<'interner> {

let definition = Definition::Local(id);
let mutable = false;
ast::Expression::Ident(ast::Ident { definition, mutable, location: None, name, typ })
ast::Expression::Ident(ast::Ident {
definition,
mutable,
location: None,
name,
typ,
id: self.next_ident_id(),
})
});

// Finally we can return the created Tuple from the new block
Expand Down Expand Up @@ -899,8 +926,9 @@ impl<'interner> Monomorphizer<'interner> {

let typ = Self::convert_type(tuple_type, location)?;
let location = Some(location);
let id = self.next_ident_id();
let new_rhs =
ast::Expression::Ident(ast::Ident { location, mutable, definition, name, typ });
ast::Expression::Ident(ast::Ident { location, mutable, definition, name, typ, id });

let new_rhs = ast::Expression::ExtractTupleField(Box::new(new_rhs), i);
let new_expr = self.unpack_pattern(field_pattern, new_rhs, &field_type)?;
Expand Down Expand Up @@ -947,7 +975,8 @@ impl<'interner> Monomorphizer<'interner> {
};

let typ = Self::convert_type(typ, ident.location)?;
Ok(Some(ast::Ident { location: Some(ident.location), mutable, definition, name, typ }))
let id = self.next_ident_id();
Ok(Some(ast::Ident { location: Some(ident.location), mutable, definition, name, typ, id }))
}

fn ident(
Expand Down Expand Up @@ -996,7 +1025,9 @@ impl<'interner> Monomorphizer<'interner> {
None,
);
let typ = Self::convert_type(&typ, ident.location)?;
let ident = ast::Ident { location, mutable, definition, name, typ: typ.clone() };
let id = self.next_ident_id();
let ident =
ast::Ident { location, mutable, definition, name, typ: typ.clone(), id };
let ident_expression = ast::Expression::Ident(ident);
if self.is_function_closure_type(&typ) {
ast::Expression::Tuple(vec![
Expand Down Expand Up @@ -1076,6 +1107,7 @@ impl<'interner> Monomorphizer<'interner> {
mutable: false,
name,
typ,
id: self.next_ident_id(),
};
ast::Expression::Ident(ident)
} else {
Expand Down Expand Up @@ -1111,6 +1143,7 @@ impl<'interner> Monomorphizer<'interner> {
mutable: false,
name,
typ,
id: self.next_ident_id(),
};
ast::Expression::Ident(ident)
} else {
Expand Down Expand Up @@ -1593,6 +1626,7 @@ impl<'interner> Monomorphizer<'interner> {
location: None,
name: the_trait.methods[method.method_index].name.to_string(),
typ: Self::convert_type(&function_type, location)?,
id: self.next_ident_id(),
}))
}

Expand Down Expand Up @@ -1649,6 +1683,7 @@ impl<'interner> Monomorphizer<'interner> {
mutable: false,
name: "tmp".to_string(),
typ: Self::convert_type(&self.interner.id_type(call.func), location)?,
id: self.next_ident_id(),
});

let env_argument =
Expand Down Expand Up @@ -1966,6 +2001,7 @@ impl<'interner> Monomorphizer<'interner> {
location: None,
name,
typ,
id: self.next_ident_id(),
}))
}

Expand Down Expand Up @@ -2049,6 +2085,7 @@ impl<'interner> Monomorphizer<'interner> {
definition,
name: env_name.to_string(),
typ: env_typ.clone(),
id: self.next_ident_id(),
};

self.lambda_envs_stack
Expand All @@ -2068,6 +2105,7 @@ impl<'interner> Monomorphizer<'interner> {
location: None, // TODO: This should match the location of the lambda expression
name: name.clone(),
typ: lambda_fn_typ.clone(),
id: self.next_ident_id(),
});

let mut parameters = vec![(env_local_id, true, env_name.to_string(), env_typ.clone())];
Expand Down Expand Up @@ -2104,6 +2142,7 @@ impl<'interner> Monomorphizer<'interner> {
definition: closure_definition,
name: block_ident_name.to_string(),
typ: ast::Type::Tuple(vec![env_typ, lambda_fn_typ]),
id: self.next_ident_id(),
});

Ok((block_let_stmt, closure_ident))
Expand Down Expand Up @@ -2285,6 +2324,7 @@ impl<'interner> Monomorphizer<'interner> {
Box::new(env_type.clone()),
unconstrained,
),
id: self.next_ident_id(),
})
}

Expand Down
14 changes: 5 additions & 9 deletions compiler/noirc_frontend/src/monomorphization/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,11 @@ impl AstPrinter {
})
.unwrap_or_default();

write!(
f,
"{}fn {}({}) -> {}{} {{",
if function.unconstrained { "unconstrained " } else { "" },
self.fmt_func(&function.name, function.id),
params,
vis,
function.return_type,
)?;
let unconstrained = if function.unconstrained { "unconstrained " } else { "" };
let name = self.fmt_func(&function.name, function.id);
let return_type = &function.return_type;

write!(f, "{unconstrained}fn {name}({params}) -> {vis}{return_type} {{",)?;
self.in_unconstrained = function.unconstrained;
self.indent_level += 1;
self.print_expr_expect_block(&function.body, f)?;
Expand Down
2 changes: 1 addition & 1 deletion compiler/noirc_frontend/src/monomorphization/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#[macro_export]
macro_rules! get_monomorphized {
($src:expr, $expect:expr) => {
$crate::test_utils::get_monomorphized($src, $crate::function_path!(), $expect)
$crate::test_utils::get_monomorphized($src, Some($crate::function_path!()), $expect)
};
}

Expand Down Expand Up @@ -91,12 +91,12 @@
Zero,
^^^^ Type `Odd` is recursive
~~~~ All types in Noir must have a known size at compile-time
Succ(Odd),

Check warning on line 94 in compiler/noirc_frontend/src/monomorphization/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Succ)
}

enum Odd {
One,
Succ(Even),

Check warning on line 99 in compiler/noirc_frontend/src/monomorphization/tests.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (Succ)
}
";
let features = vec![UnstableFeature::Enums];
Expand Down
Loading
Loading