Skip to content

Commit b0cc82f

Browse files
committed
[1 changes] fix(mem2reg): Handle aliases in function last store cleanup and additional alias unit test (noir-lang/noir#5967)
fix: let `derive(Eq)` work for empty structs (noir-lang/noir#5965) feat: add `FunctionDefinition` methods `is_unconstrained` and `set_unconstrained` (noir-lang/noir#5962) feat: LSP autocompletion for attributes (noir-lang/noir#5963) feat: `Module::add_item` (noir-lang/noir#5947) feat: Add `StructDefinition::add_generic` (noir-lang/noir#5961) feat: Add `StructDefinition::name` (noir-lang/noir#5960) fix(mem2reg): Handle aliases better when setting a known value for a load (noir-lang/noir#5959) feat: Arithmetic Generics (noir-lang/noir#5950) feat: add `FunctionDefinition::module` and `StructDefinition::module` (noir-lang/noir#5956) feat: LSP now suggests self fields and methods (noir-lang/noir#5955)
1 parent 05cc59f commit b0cc82f

File tree

63 files changed

+1705
-953
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1705
-953
lines changed

.noir-sync-commit

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
b84009ca428a5790acf53a6c027146b706170574
1+
36756e8757ad40e2b231747ed754273f50e5dc2f

noir/noir-repo/.gitattributes

-1
This file was deleted.

noir/noir-repo/acvm-repo/acvm_js/build.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function run_if_available {
2525
require_command jq
2626
require_command cargo
2727
require_command wasm-bindgen
28-
#require_command wasm-opt
28+
require_command wasm-opt
2929

3030
self_path=$(dirname "$(readlink -f "$0")")
3131
pname=$(cargo read-manifest | jq -r '.name')

noir/noir-repo/aztec_macros/src/utils/hir_utils.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ pub fn inject_fn(
195195
let trait_id = None;
196196
items.functions.push(UnresolvedFunctions { file_id, functions, trait_id, self_type: None });
197197

198-
let mut errors = Elaborator::elaborate(context, *crate_id, items, None, false);
198+
let mut errors = Elaborator::elaborate(context, *crate_id, items, None);
199199
errors.retain(|(error, _)| !CustomDiagnostic::from(error).is_warning());
200200

201201
if !errors.is_empty() {
@@ -241,7 +241,7 @@ pub fn inject_global(
241241
let mut items = CollectedItems::default();
242242
items.globals.push(UnresolvedGlobal { file_id, module_id, global_id, stmt_def: global });
243243

244-
let _errors = Elaborator::elaborate(context, *crate_id, items, None, false);
244+
let _errors = Elaborator::elaborate(context, *crate_id, items, None);
245245
}
246246

247247
pub fn fully_qualified_note_path(context: &HirContext, note_id: StructId) -> Option<String> {

noir/noir-repo/compiler/noirc_driver/src/lib.rs

-5
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,6 @@ pub struct CompileOptions {
120120
#[arg(long, hide = true)]
121121
pub show_artifact_paths: bool,
122122

123-
/// Temporary flag to enable the experimental arithmetic generics feature
124-
#[arg(long, hide = true)]
125-
pub arithmetic_generics: bool,
126-
127123
/// Flag to turn off the compiler check for under constrained values.
128124
/// Warning: This can improve compilation speed but can also lead to correctness errors.
129125
/// This check should always be run on production code.
@@ -289,7 +285,6 @@ pub fn check_crate(
289285
crate_id,
290286
context,
291287
options.debug_comptime_in_file.as_deref(),
292-
options.arithmetic_generics,
293288
error_on_unused_imports,
294289
macros,
295290
);

noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs

+107-8
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,12 @@ impl<'f> PerFunctionContext<'f> {
181181
self.last_loads.get(store_address).is_none()
182182
};
183183

184-
if remove_load && !is_reference_param {
184+
let is_reference_alias = block
185+
.expressions
186+
.get(store_address)
187+
.map_or(false, |expression| matches!(expression, Expression::Dereference(_)));
188+
189+
if remove_load && !is_reference_param && !is_reference_alias {
185190
self.instructions_to_remove.insert(*store_instruction);
186191
}
187192
}
@@ -286,19 +291,19 @@ impl<'f> PerFunctionContext<'f> {
286291
} else {
287292
references.mark_value_used(address, self.inserter.function);
288293

289-
let expression = if let Some(expression) = references.expressions.get(&result) {
290-
expression.clone()
291-
} else {
292-
references.expressions.insert(result, Expression::Other(result));
293-
Expression::Other(result)
294-
};
295-
if let Some(aliases) = references.aliases.get_mut(&expression) {
294+
let expression =
295+
references.expressions.entry(result).or_insert(Expression::Other(result));
296+
// Make sure this load result is marked an alias to itself
297+
if let Some(aliases) = references.aliases.get_mut(expression) {
298+
// If we have an alias set, add to the set
296299
aliases.insert(result);
297300
} else {
301+
// Otherwise, create a new alias set containing just the load result
298302
references
299303
.aliases
300304
.insert(Expression::Other(result), AliasSet::known(result));
301305
}
306+
// Mark that we know a load result is equivalent to the address of a load.
302307
references.set_known_value(result, address);
303308

304309
self.last_loads.insert(address, (instruction, block_id));
@@ -789,4 +794,98 @@ mod tests {
789794
// We expect the last eq to be optimized out
790795
assert_eq!(b1_instructions.len(), 0);
791796
}
797+
798+
#[test]
799+
fn keep_store_to_alias_in_loop_block() {
800+
// This test makes sure the instruction `store Field 2 at v5` in b2 remains after mem2reg.
801+
// Although the only instruction on v5 is a lone store without any loads,
802+
// v5 is an alias of the reference v0 which is stored in v2.
803+
// This test makes sure that we are not inadvertently removing stores to aliases across blocks.
804+
//
805+
// acir(inline) fn main f0 {
806+
// b0():
807+
// v0 = allocate
808+
// store Field 0 at v0
809+
// v2 = allocate
810+
// store v0 at v2
811+
// jmp b1(Field 0)
812+
// b1(v3: Field):
813+
// v4 = eq v3, Field 0
814+
// jmpif v4 then: b2, else: b3
815+
// b2():
816+
// v5 = load v2
817+
// store Field 2 at v5
818+
// v8 = add v3, Field 1
819+
// jmp b1(v8)
820+
// b3():
821+
// v9 = load v0
822+
// v10 = eq v9, Field 2
823+
// constrain v9 == Field 2
824+
// v11 = load v2
825+
// v12 = load v10
826+
// v13 = eq v12, Field 2
827+
// constrain v11 == Field 2
828+
// return
829+
// }
830+
let main_id = Id::test_new(0);
831+
let mut builder = FunctionBuilder::new("main".into(), main_id);
832+
833+
let v0 = builder.insert_allocate(Type::field());
834+
let zero = builder.numeric_constant(0u128, Type::field());
835+
builder.insert_store(v0, zero);
836+
837+
let v2 = builder.insert_allocate(Type::field());
838+
// Construct alias
839+
builder.insert_store(v2, v0);
840+
let v2_type = builder.current_function.dfg.type_of_value(v2);
841+
assert!(builder.current_function.dfg.value_is_reference(v2));
842+
843+
let b1 = builder.insert_block();
844+
builder.terminate_with_jmp(b1, vec![zero]);
845+
846+
// Loop header
847+
builder.switch_to_block(b1);
848+
let v3 = builder.add_block_parameter(b1, Type::field());
849+
let is_zero = builder.insert_binary(v3, BinaryOp::Eq, zero);
850+
851+
let b2 = builder.insert_block();
852+
let b3 = builder.insert_block();
853+
builder.terminate_with_jmpif(is_zero, b2, b3);
854+
855+
// Loop body
856+
builder.switch_to_block(b2);
857+
let v5 = builder.insert_load(v2, v2_type.clone());
858+
let two = builder.numeric_constant(2u128, Type::field());
859+
builder.insert_store(v5, two);
860+
let one = builder.numeric_constant(1u128, Type::field());
861+
let v3_plus_one = builder.insert_binary(v3, BinaryOp::Add, one);
862+
builder.terminate_with_jmp(b1, vec![v3_plus_one]);
863+
864+
builder.switch_to_block(b3);
865+
let v9 = builder.insert_load(v0, Type::field());
866+
let _ = builder.insert_binary(v9, BinaryOp::Eq, two);
867+
868+
builder.insert_constrain(v9, two, None);
869+
let v11 = builder.insert_load(v2, v2_type);
870+
let v12 = builder.insert_load(v11, Type::field());
871+
let _ = builder.insert_binary(v12, BinaryOp::Eq, two);
872+
873+
builder.insert_constrain(v11, two, None);
874+
builder.terminate_with_return(vec![]);
875+
876+
let ssa = builder.finish();
877+
878+
// We expect the same result as above.
879+
let ssa = ssa.mem2reg();
880+
881+
let main = ssa.main();
882+
assert_eq!(main.reachable_blocks().len(), 4);
883+
884+
// The store from the original SSA should remain
885+
assert_eq!(count_stores(main.entry_block(), &main.dfg), 2);
886+
assert_eq!(count_stores(b2, &main.dfg), 1);
887+
888+
assert_eq!(count_loads(b2, &main.dfg), 1);
889+
assert_eq!(count_loads(b3, &main.dfg), 3);
890+
}
792891
}

noir/noir-repo/compiler/noirc_frontend/src/ast/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod traits;
1212
mod type_alias;
1313
mod visitor;
1414

15+
pub use visitor::AttributeTarget;
1516
pub use visitor::Visitor;
1617

1718
pub use expression::*;

noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs

+50-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::{
1616
QuotedTypeId,
1717
},
1818
parser::{Item, ItemKind, ParsedSubModule},
19-
token::{SecondaryAttribute, Tokens},
19+
token::{CustomAtrribute, SecondaryAttribute, Tokens},
2020
ParsedModule, QuotedType,
2121
};
2222

@@ -26,6 +26,13 @@ use super::{
2626
UnresolvedTypeExpression,
2727
};
2828

29+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
30+
pub enum AttributeTarget {
31+
Module,
32+
Struct,
33+
Function,
34+
}
35+
2936
/// Implements the [Visitor pattern](https://en.wikipedia.org/wiki/Visitor_pattern) for Noir's AST.
3037
///
3138
/// In this implementation, methods must return a bool:
@@ -433,7 +440,15 @@ pub trait Visitor {
433440
true
434441
}
435442

436-
fn visit_secondary_attribute(&mut self, _: &SecondaryAttribute, _: Span) {}
443+
fn visit_secondary_attribute(
444+
&mut self,
445+
_: &SecondaryAttribute,
446+
_target: AttributeTarget,
447+
) -> bool {
448+
true
449+
}
450+
451+
fn visit_custom_attribute(&mut self, _: &CustomAtrribute, _target: AttributeTarget) {}
437452
}
438453

439454
impl ParsedModule {
@@ -484,14 +499,18 @@ impl Item {
484499
module_declaration.accept(self.span, visitor);
485500
}
486501
ItemKind::InnerAttribute(attribute) => {
487-
attribute.accept(self.span, visitor);
502+
attribute.accept(AttributeTarget::Module, visitor);
488503
}
489504
}
490505
}
491506
}
492507

493508
impl ParsedSubModule {
494509
pub fn accept(&self, span: Span, visitor: &mut impl Visitor) {
510+
for attribute in &self.outer_attributes {
511+
attribute.accept(AttributeTarget::Module, visitor);
512+
}
513+
495514
if visitor.visit_parsed_submodule(self, span) {
496515
self.accept_children(visitor);
497516
}
@@ -510,6 +529,10 @@ impl NoirFunction {
510529
}
511530

512531
pub fn accept_children(&self, visitor: &mut impl Visitor) {
532+
for attribute in self.secondary_attributes() {
533+
attribute.accept(AttributeTarget::Function, visitor);
534+
}
535+
513536
for param in &self.def.parameters {
514537
param.typ.accept(visitor);
515538
}
@@ -674,6 +697,10 @@ impl NoirStruct {
674697
}
675698

676699
pub fn accept_children(&self, visitor: &mut impl Visitor) {
700+
for attribute in &self.attributes {
701+
attribute.accept(AttributeTarget::Struct, visitor);
702+
}
703+
677704
for (_name, unresolved_type) in &self.fields {
678705
unresolved_type.accept(visitor);
679706
}
@@ -694,6 +721,10 @@ impl NoirTypeAlias {
694721

695722
impl ModuleDeclaration {
696723
pub fn accept(&self, span: Span, visitor: &mut impl Visitor) {
724+
for attribute in &self.outer_attributes {
725+
attribute.accept(AttributeTarget::Module, visitor);
726+
}
727+
697728
visitor.visit_module_declaration(self, span);
698729
}
699730
}
@@ -1295,8 +1326,22 @@ impl Pattern {
12951326
}
12961327

12971328
impl SecondaryAttribute {
1298-
pub fn accept(&self, span: Span, visitor: &mut impl Visitor) {
1299-
visitor.visit_secondary_attribute(self, span);
1329+
pub fn accept(&self, target: AttributeTarget, visitor: &mut impl Visitor) {
1330+
if visitor.visit_secondary_attribute(self, target) {
1331+
self.accept_children(target, visitor);
1332+
}
1333+
}
1334+
1335+
pub fn accept_children(&self, target: AttributeTarget, visitor: &mut impl Visitor) {
1336+
if let SecondaryAttribute::Custom(custom) = self {
1337+
custom.accept(target, visitor);
1338+
}
1339+
}
1340+
}
1341+
1342+
impl CustomAtrribute {
1343+
pub fn accept(&self, target: AttributeTarget, visitor: &mut impl Visitor) {
1344+
visitor.visit_custom_attribute(self, target);
13001345
}
13011346
}
13021347

0 commit comments

Comments
 (0)