Skip to content

Commit d727816

Browse files
authored
Merge 09e2b5d into 0e8becc
2 parents 0e8becc + 09e2b5d commit d727816

File tree

20 files changed

+91
-71
lines changed

20 files changed

+91
-71
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ color-eyre = "0.6.2"
154154
rand = "0.8.5"
155155
proptest = "1.2.0"
156156
proptest-derive = "0.4.0"
157+
rayon = "1.8.0"
157158

158159
im = { version = "15.1", features = ["serde"] }
159160
tracing = "0.1.40"

compiler/noirc_evaluator/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ serde_json.workspace = true
2626
serde_with = "3.2.0"
2727
tracing.workspace = true
2828
chrono = "0.4.37"
29+
rayon.workspace = true
2930
cfg-if.workspace = true
3031

3132
[dev-dependencies]

compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use acvm::{acir::AcirField, FieldElement};
2222
use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet};
2323
use iter_extended::vecmap;
2424
use num_bigint::BigUint;
25-
use std::rc::Rc;
25+
use std::sync::Arc;
2626

2727
use super::brillig_black_box::convert_black_box_call;
2828
use super::brillig_block_variables::BlockVariables;
@@ -1701,7 +1701,7 @@ impl<'block> BrilligBlock<'block> {
17011701

17021702
fn initialize_constant_array_runtime(
17031703
&mut self,
1704-
item_types: Rc<Vec<Type>>,
1704+
item_types: Arc<Vec<Type>>,
17051705
item_to_repeat: Vec<ValueId>,
17061706
item_count: usize,
17071707
pointer: MemoryAddress,

compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs

+38-19
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,36 @@
11
//! This module defines an SSA pass that detects if the final function has any subgraphs independent from inputs and outputs.
22
//! If this is the case, then part of the final circuit can be completely replaced by any other passing circuit, since there are no constraints ensuring connections.
33
//! So the compiler informs the developer of this as a bug
4-
use im::HashMap;
5-
64
use crate::errors::{InternalBug, SsaReport};
75
use crate::ssa::ir::basic_block::BasicBlockId;
86
use crate::ssa::ir::function::RuntimeType;
97
use crate::ssa::ir::function::{Function, FunctionId};
108
use crate::ssa::ir::instruction::{Instruction, InstructionId, Intrinsic};
119
use crate::ssa::ir::value::{Value, ValueId};
1210
use crate::ssa::ssa_gen::Ssa;
11+
use im::HashMap;
12+
use rayon::prelude::*;
1313
use std::collections::{BTreeMap, HashSet};
1414

1515
impl Ssa {
1616
/// Go through each top-level non-brillig function and detect if it has independent subgraphs
1717
#[tracing::instrument(level = "trace", skip(self))]
1818
pub(crate) fn check_for_underconstrained_values(&mut self) -> Vec<SsaReport> {
19-
let mut warnings: Vec<SsaReport> = Vec::new();
20-
for function in self.functions.values() {
21-
match function.runtime() {
22-
RuntimeType::Acir { .. } => {
23-
warnings.extend(check_for_underconstrained_values_within_function(
24-
function,
19+
let functions_id = self.functions.values().map(|f| f.id().to_usize()).collect::<Vec<_>>();
20+
functions_id
21+
.iter()
22+
.par_bridge()
23+
.flat_map(|fid| {
24+
let function_to_process = &self.functions[&FunctionId::new(*fid)];
25+
match function_to_process.runtime() {
26+
RuntimeType::Acir { .. } => check_for_underconstrained_values_within_function(
27+
function_to_process,
2528
&self.functions,
26-
));
29+
),
30+
RuntimeType::Brillig => Vec::new(),
2731
}
28-
RuntimeType::Brillig => (),
29-
}
30-
}
31-
warnings
32+
})
33+
.collect()
3234
}
3335
}
3436

@@ -88,9 +90,8 @@ impl Context {
8890
self.visited_blocks.insert(block);
8991
self.connect_value_ids_in_block(function, block, all_functions);
9092
}
91-
9293
// Merge ValueIds into sets, where each original small set of ValueIds is merged with another set if they intersect
93-
self.merge_sets();
94+
self.value_sets = Self::merge_sets_par(&self.value_sets);
9495
}
9596

9697
/// Find sets that contain input or output value of the function
@@ -267,14 +268,13 @@ impl Context {
267268
/// Merge all small sets into larger ones based on whether the sets intersect or not
268269
///
269270
/// If two small sets have a common ValueId, we merge them into one
270-
fn merge_sets(&mut self) {
271+
fn merge_sets(current: &[HashSet<ValueId>]) -> Vec<HashSet<ValueId>> {
271272
let mut new_set_id: usize = 0;
272273
let mut updated_sets: HashMap<usize, HashSet<ValueId>> = HashMap::new();
273274
let mut value_dictionary: HashMap<ValueId, usize> = HashMap::new();
274275
let mut parsed_value_set: HashSet<ValueId> = HashSet::new();
275276

276-
// Go through each set
277-
for set in self.value_sets.iter() {
277+
for set in current.iter() {
278278
// Check if the set has any of the ValueIds we've encountered at previous iterations
279279
let intersection: HashSet<ValueId> =
280280
set.intersection(&parsed_value_set).copied().collect();
@@ -327,7 +327,26 @@ impl Context {
327327
}
328328
updated_sets.insert(largest_set_index, largest_set);
329329
}
330-
self.value_sets = updated_sets.values().cloned().collect();
330+
updated_sets.values().cloned().collect()
331+
}
332+
333+
/// Parallel version of merge_sets
334+
/// The sets are merged by chunks, and then the chunks are merged together
335+
fn merge_sets_par(sets: &[HashSet<ValueId>]) -> Vec<HashSet<ValueId>> {
336+
let mut sets = sets.to_owned();
337+
let mut len = sets.len();
338+
let mut prev_len = len + 1;
339+
340+
while len > 1000 && len < prev_len {
341+
sets = sets.par_chunks(1000).flat_map(Self::merge_sets).collect();
342+
343+
prev_len = len;
344+
len = sets.len();
345+
}
346+
// TODO: if prev_len >= len, this means we cannot effectively merge the sets anymore
347+
// We should instead partition the sets into disjoint chunks and work on those chunks,
348+
// but for now we fallback to the non-parallel implementation
349+
Self::merge_sets(&sets)
331350
}
332351
}
333352
#[cfg(test)]

compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use std::collections::BTreeMap;
2-
use std::rc::Rc;
1+
use std::{collections::BTreeMap, sync::Arc};
32

43
use crate::ssa::ir::{types::Type, value::ValueId};
54
use acvm::FieldElement;
@@ -155,8 +154,8 @@ impl FunctionBuilder {
155154
let len = databus.values.len();
156155

157156
let array = if len > 0 {
158-
let array =
159-
self.array_constant(databus.values, Type::Array(Rc::new(vec![Type::field()]), len));
157+
let array = self
158+
.array_constant(databus.values, Type::Array(Arc::new(vec![Type::field()]), len));
160159
Some(array)
161160
} else {
162161
None

compiler/noirc_evaluator/src/ssa/function_builder/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pub(crate) mod data_bus;
22

3-
use std::{borrow::Cow, collections::BTreeMap, rc::Rc};
3+
use std::{borrow::Cow, collections::BTreeMap, sync::Arc};
44

55
use acvm::{acir::circuit::ErrorSelector, FieldElement};
66
use noirc_errors::Location;
@@ -189,7 +189,7 @@ impl FunctionBuilder {
189189
/// given amount of field elements. Returns the result of the allocate instruction,
190190
/// which is always a Reference to the allocated data.
191191
pub(crate) fn insert_allocate(&mut self, element_type: Type) -> ValueId {
192-
let reference_type = Type::Reference(Rc::new(element_type));
192+
let reference_type = Type::Reference(Arc::new(element_type));
193193
self.insert_instruction(Instruction::Allocate, Some(vec![reference_type])).first()
194194
}
195195

@@ -516,7 +516,7 @@ impl std::ops::Index<BasicBlockId> for FunctionBuilder {
516516

517517
#[cfg(test)]
518518
mod tests {
519-
use std::rc::Rc;
519+
use std::sync::Arc;
520520

521521
use acvm::{acir::AcirField, FieldElement};
522522

@@ -542,7 +542,7 @@ mod tests {
542542
let to_bits_id = builder.import_intrinsic_id(Intrinsic::ToBits(Endian::Little));
543543
let input = builder.numeric_constant(FieldElement::from(7_u128), Type::field());
544544
let length = builder.numeric_constant(FieldElement::from(8_u128), Type::field());
545-
let result_types = vec![Type::Array(Rc::new(vec![Type::bool()]), 8)];
545+
let result_types = vec![Type::Array(Arc::new(vec![Type::bool()]), 8)];
546546
let call_results =
547547
builder.insert_call(to_bits_id, vec![input, length], result_types).into_owned();
548548

compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use fxhash::FxHashMap as HashMap;
2-
use std::{collections::VecDeque, rc::Rc};
2+
use std::{collections::VecDeque, sync::Arc};
33

44
use acvm::{
55
acir::{AcirField, BlackBoxFunc},
@@ -561,7 +561,7 @@ fn simplify_black_box_func(
561561
fn make_constant_array(dfg: &mut DataFlowGraph, results: Vec<FieldElement>, typ: Type) -> ValueId {
562562
let result_constants = vecmap(results, |element| dfg.make_constant(element, typ.clone()));
563563

564-
let typ = Type::Array(Rc::new(vec![typ]), result_constants.len());
564+
let typ = Type::Array(Arc::new(vec![typ]), result_constants.len());
565565
dfg.make_array(result_constants.into(), typ)
566566
}
567567

@@ -572,7 +572,7 @@ fn make_constant_slice(
572572
) -> (ValueId, ValueId) {
573573
let result_constants = vecmap(results, |element| dfg.make_constant(element, typ.clone()));
574574

575-
let typ = Type::Slice(Rc::new(vec![typ]));
575+
let typ = Type::Slice(Arc::new(vec![typ]));
576576
let length = FieldElement::from(result_constants.len() as u128);
577577
(dfg.make_constant(length, Type::length_type()), dfg.make_array(result_constants.into(), typ))
578578
}

compiler/noirc_evaluator/src/ssa/ir/instruction/call/blackbox.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::rc::Rc;
1+
use std::sync::Arc;
22

33
use acvm::{acir::AcirField, BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement};
44
use iter_extended::vecmap;
@@ -45,7 +45,7 @@ pub(super) fn simplify_ec_add(
4545
let result_y = dfg.make_constant(result_y, Type::field());
4646
let result_is_infinity = dfg.make_constant(result_is_infinity, Type::bool());
4747

48-
let typ = Type::Array(Rc::new(vec![Type::field()]), 3);
48+
let typ = Type::Array(Arc::new(vec![Type::field()]), 3);
4949
let result_array =
5050
dfg.make_array(im::vector![result_x, result_y, result_is_infinity], typ);
5151

compiler/noirc_evaluator/src/ssa/ir/map.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ impl<T> Id<T> {
2727
/// Constructs a new Id for the given index.
2828
/// This constructor is deliberately private to prevent
2929
/// constructing invalid IDs.
30-
fn new(index: usize) -> Self {
30+
pub(crate) fn new(index: usize) -> Self {
3131
Self { index, _marker: std::marker::PhantomData }
3232
}
3333

compiler/noirc_evaluator/src/ssa/ir/types.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use serde::{Deserialize, Serialize};
2-
use std::rc::Rc;
2+
use std::sync::Arc;
33

44
use acvm::{acir::AcirField, FieldElement};
55
use iter_extended::vecmap;
@@ -72,13 +72,13 @@ pub(crate) enum Type {
7272
Numeric(NumericType),
7373

7474
/// A reference to some value, such as an array
75-
Reference(Rc<Type>),
75+
Reference(Arc<Type>),
7676

7777
/// An immutable array value with the given element type and length
78-
Array(Rc<CompositeType>, usize),
78+
Array(Arc<CompositeType>, usize),
7979

8080
/// An immutable slice value with a given element type
81-
Slice(Rc<CompositeType>),
81+
Slice(Arc<CompositeType>),
8282

8383
/// A function that may be called directly
8484
Function,
@@ -112,7 +112,7 @@ impl Type {
112112

113113
/// Creates the str<N> type, of the given length N
114114
pub(crate) fn str(length: usize) -> Type {
115-
Type::Array(Rc::new(vec![Type::char()]), length)
115+
Type::Array(Arc::new(vec![Type::char()]), length)
116116
}
117117

118118
/// Creates the native field type.
@@ -190,7 +190,7 @@ impl Type {
190190
}
191191
}
192192

193-
pub(crate) fn element_types(self) -> Rc<Vec<Type>> {
193+
pub(crate) fn element_types(self) -> Arc<Vec<Type>> {
194194
match self {
195195
Type::Array(element_types, _) | Type::Slice(element_types) => element_types,
196196
other => panic!("element_types: Expected array or slice, found {other}"),

compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ impl Context {
311311

312312
#[cfg(test)]
313313
mod test {
314-
use std::rc::Rc;
314+
use std::sync::Arc;
315315

316316
use crate::ssa::{
317317
function_builder::FunctionBuilder,
@@ -509,7 +509,7 @@ mod test {
509509
let one = builder.field_constant(1u128);
510510
let v1 = builder.insert_binary(v0, BinaryOp::Add, one);
511511

512-
let array_type = Type::Array(Rc::new(vec![Type::field()]), 1);
512+
let array_type = Type::Array(Arc::new(vec![Type::field()]), 1);
513513
let arr = builder.current_function.dfg.make_array(vec![v1].into(), array_type);
514514
builder.terminate_with_return(vec![arr]);
515515

@@ -601,7 +601,7 @@ mod test {
601601
// Compiling main
602602
let mut builder = FunctionBuilder::new("main".into(), main_id);
603603

604-
let v0 = builder.add_parameter(Type::Array(Rc::new(vec![Type::field()]), 4));
604+
let v0 = builder.add_parameter(Type::Array(Arc::new(vec![Type::field()]), 4));
605605
let v1 = builder.add_parameter(Type::unsigned(32));
606606
let v2 = builder.add_parameter(Type::unsigned(1));
607607
let v3 = builder.add_parameter(Type::unsigned(1));
@@ -737,7 +737,7 @@ mod test {
737737
let zero = builder.field_constant(0u128);
738738
let one = builder.field_constant(1u128);
739739

740-
let typ = Type::Array(Rc::new(vec![Type::field()]), 2);
740+
let typ = Type::Array(Arc::new(vec![Type::field()]), 2);
741741
let array = builder.array_constant(vec![zero, one].into(), typ);
742742

743743
let _v2 = builder.insert_array_get(array, v1, Type::field());
@@ -787,7 +787,7 @@ mod test {
787787

788788
let v0 = builder.add_parameter(Type::bool());
789789
let v1 = builder.add_parameter(Type::bool());
790-
let v2 = builder.add_parameter(Type::Array(Rc::new(vec![Type::field()]), 2));
790+
let v2 = builder.add_parameter(Type::Array(Arc::new(vec![Type::field()]), 2));
791791

792792
let zero = builder.numeric_constant(0u128, Type::length_type());
793793
let one = builder.numeric_constant(1u128, Type::length_type());

compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,7 @@ impl<'f> Context<'f> {
878878

879879
#[cfg(test)]
880880
mod test {
881-
use std::rc::Rc;
881+
use std::sync::Arc;
882882

883883
use acvm::acir::AcirField;
884884

@@ -1016,7 +1016,7 @@ mod test {
10161016
let b2 = builder.insert_block();
10171017

10181018
let v0 = builder.add_parameter(Type::bool());
1019-
let v1 = builder.add_parameter(Type::Reference(Rc::new(Type::field())));
1019+
let v1 = builder.add_parameter(Type::Reference(Arc::new(Type::field())));
10201020

10211021
builder.terminate_with_jmpif(v0, b1, b2);
10221022

@@ -1078,7 +1078,7 @@ mod test {
10781078
let b3 = builder.insert_block();
10791079

10801080
let v0 = builder.add_parameter(Type::bool());
1081-
let v1 = builder.add_parameter(Type::Reference(Rc::new(Type::field())));
1081+
let v1 = builder.add_parameter(Type::Reference(Arc::new(Type::field())));
10821082

10831083
builder.terminate_with_jmpif(v0, b1, b2);
10841084

@@ -1477,7 +1477,7 @@ mod test {
14771477
let b2 = builder.insert_block();
14781478
let b3 = builder.insert_block();
14791479

1480-
let element_type = Rc::new(vec![Type::unsigned(8)]);
1480+
let element_type = Arc::new(vec![Type::unsigned(8)]);
14811481
let array_type = Type::Array(element_type.clone(), 2);
14821482
let array = builder.add_parameter(array_type);
14831483

0 commit comments

Comments
 (0)