From 3e38dc80f58e64c04b4046ca54f82a7031fc6372 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 6 May 2022 21:56:48 +0200 Subject: [PATCH 1/7] use bitvec for group (internally) --- compiler/can/src/reference_matrix.rs | 16 +++++++++++++--- compiler/load_internal/src/file.rs | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/compiler/can/src/reference_matrix.rs b/compiler/can/src/reference_matrix.rs index 13ba3caea2..3b7a2a6f11 100644 --- a/compiler/can/src/reference_matrix.rs +++ b/compiler/can/src/reference_matrix.rs @@ -131,6 +131,16 @@ impl ReferenceMatrix { /// Get the strongly-connected components of the set of input nodes. pub fn strongly_connected_components(&self, nodes: &[u32]) -> Sccs { + let mut bitvec = BitVec::repeat(false, self.length); + + for value in nodes { + bitvec.set(*value as usize, true); + } + + self.strongly_connected_components_help(&bitvec) + } + + fn strongly_connected_components_help(&self, nodes: &BitSlice) -> Sccs { let mut params = Params::new(self.length, nodes); 'outer: loop { @@ -180,11 +190,11 @@ struct Params { } impl Params { - fn new(length: usize, group: &[u32]) -> Self { + fn new(length: usize, group: &BitSlice) -> Self { let mut preorders = vec![Preorder::Removed; length]; - for value in group { - preorders[*value as usize] = Preorder::Empty; + for index in group.iter_ones() { + preorders[index] = Preorder::Empty; } Self { diff --git a/compiler/load_internal/src/file.rs b/compiler/load_internal/src/file.rs index f97bf7d012..8e210557b8 100644 --- a/compiler/load_internal/src/file.rs +++ b/compiler/load_internal/src/file.rs @@ -1159,7 +1159,7 @@ pub fn load<'a>( ) -> Result, LoadingProblem<'a>> { // When compiling to wasm, we cannot spawn extra threads // so we have a single-threaded implementation - if threading == Threading::Single || cfg!(target_family = "wasm") { + if true || threading == Threading::Single || cfg!(target_family = "wasm") { load_single_threaded( arena, load_start, From a2b04d35f75536f12883b6dda09cb69a3eb5d846 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 6 May 2022 22:06:16 +0200 Subject: [PATCH 2/7] make params.p use a bitvec --- compiler/can/src/reference_matrix.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/can/src/reference_matrix.rs b/compiler/can/src/reference_matrix.rs index 3b7a2a6f11..8e323e2f53 100644 --- a/compiler/can/src/reference_matrix.rs +++ b/compiler/can/src/reference_matrix.rs @@ -183,10 +183,10 @@ enum Preorder { struct Params { preorders: Vec, c: usize, - p: Vec, + p: BitVec, s: Vec, scc: Sccs, - scca: Vec, + scca: BitVec, } impl Params { @@ -201,12 +201,12 @@ impl Params { preorders, c: 0, s: Vec::new(), - p: Vec::new(), + p: BitVec::repeat(false, length), scc: Sccs { matrix: ReferenceMatrix::new(length), components: 0, }, - scca: Vec::new(), + scca: BitVec::repeat(false, length), } } } @@ -217,19 +217,19 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { params.c += 1; params.s.push(v as u32); - params.p.push(v as u32); + params.p.set(v, true); for w in bitvec[v * length..][..length].iter_ones() { - if !params.scca.contains(&(w as u32)) { + if !params.scca[w] { match params.preorders[w] { Preorder::Filled(pw) => loop { - let index = *params.p.last().unwrap(); + let index = params.p.last_one().unwrap(); match params.preorders[index as usize] { Preorder::Empty => unreachable!(), Preorder::Filled(current) => { if current > pw { - params.p.pop(); + params.p.set(index, false); } else { break; } @@ -243,15 +243,15 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { } } - if params.p.last() == Some(&(v as u32)) { - params.p.pop(); + if params.p.last_one() == Some(v) { + params.p.set(v, false); while let Some(node) = params.s.pop() { params .scc .matrix .set_row_col(params.scc.components, node as usize, true); - params.scca.push(node); + params.scca.set(node as usize, true); params.preorders[node as usize] = Preorder::Removed; if node as usize == v { break; From 65ca5d33b3025c4086a8a17e03b40e431e59aa73 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 6 May 2022 22:23:32 +0200 Subject: [PATCH 3/7] use bitvec for params.s --- compiler/can/src/reference_matrix.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/compiler/can/src/reference_matrix.rs b/compiler/can/src/reference_matrix.rs index 8e323e2f53..346c1d194e 100644 --- a/compiler/can/src/reference_matrix.rs +++ b/compiler/can/src/reference_matrix.rs @@ -184,7 +184,7 @@ struct Params { preorders: Vec, c: usize, p: BitVec, - s: Vec, + s: BitVec, scc: Sccs, scca: BitVec, } @@ -200,7 +200,7 @@ impl Params { Self { preorders, c: 0, - s: Vec::new(), + s: BitVec::repeat(false, length), p: BitVec::repeat(false, length), scc: Sccs { matrix: ReferenceMatrix::new(length), @@ -216,7 +216,7 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { params.c += 1; - params.s.push(v as u32); + params.s.set(v, true); params.p.set(v, true); for w in bitvec[v * length..][..length].iter_ones() { @@ -246,14 +246,16 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { if params.p.last_one() == Some(v) { params.p.set(v, false); - while let Some(node) = params.s.pop() { + while let Some(node) = params.s.last_one() { + params.s.set(node, false); + params .scc .matrix - .set_row_col(params.scc.components, node as usize, true); - params.scca.set(node as usize, true); - params.preorders[node as usize] = Preorder::Removed; - if node as usize == v { + .set_row_col(params.scc.components, node, true); + params.scca.set(node, true); + params.preorders[node] = Preorder::Removed; + if node == v { break; } } From 2b1491189abe3ba179890e9273b898b1ffe78e03 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 6 May 2022 22:48:59 +0200 Subject: [PATCH 4/7] Revert "use bitvec for params.s" This reverts commit 65ca5d33b3025c4086a8a17e03b40e431e59aa73. --- compiler/can/src/reference_matrix.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/can/src/reference_matrix.rs b/compiler/can/src/reference_matrix.rs index 346c1d194e..8e323e2f53 100644 --- a/compiler/can/src/reference_matrix.rs +++ b/compiler/can/src/reference_matrix.rs @@ -184,7 +184,7 @@ struct Params { preorders: Vec, c: usize, p: BitVec, - s: BitVec, + s: Vec, scc: Sccs, scca: BitVec, } @@ -200,7 +200,7 @@ impl Params { Self { preorders, c: 0, - s: BitVec::repeat(false, length), + s: Vec::new(), p: BitVec::repeat(false, length), scc: Sccs { matrix: ReferenceMatrix::new(length), @@ -216,7 +216,7 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { params.c += 1; - params.s.set(v, true); + params.s.push(v as u32); params.p.set(v, true); for w in bitvec[v * length..][..length].iter_ones() { @@ -246,16 +246,14 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { if params.p.last_one() == Some(v) { params.p.set(v, false); - while let Some(node) = params.s.last_one() { - params.s.set(node, false); - + while let Some(node) = params.s.pop() { params .scc .matrix - .set_row_col(params.scc.components, node, true); - params.scca.set(node, true); - params.preorders[node] = Preorder::Removed; - if node == v { + .set_row_col(params.scc.components, node as usize, true); + params.scca.set(node as usize, true); + params.preorders[node as usize] = Preorder::Removed; + if node as usize == v { break; } } From b46de2f0a86fce3f5fe015fe8c5e376f74882a46 Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 6 May 2022 22:55:06 +0200 Subject: [PATCH 5/7] Revert "make params.p use a bitvec" This reverts commit a2b04d35f75536f12883b6dda09cb69a3eb5d846. --- compiler/can/src/reference_matrix.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/compiler/can/src/reference_matrix.rs b/compiler/can/src/reference_matrix.rs index 8e323e2f53..3b7a2a6f11 100644 --- a/compiler/can/src/reference_matrix.rs +++ b/compiler/can/src/reference_matrix.rs @@ -183,10 +183,10 @@ enum Preorder { struct Params { preorders: Vec, c: usize, - p: BitVec, + p: Vec, s: Vec, scc: Sccs, - scca: BitVec, + scca: Vec, } impl Params { @@ -201,12 +201,12 @@ impl Params { preorders, c: 0, s: Vec::new(), - p: BitVec::repeat(false, length), + p: Vec::new(), scc: Sccs { matrix: ReferenceMatrix::new(length), components: 0, }, - scca: BitVec::repeat(false, length), + scca: Vec::new(), } } } @@ -217,19 +217,19 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { params.c += 1; params.s.push(v as u32); - params.p.set(v, true); + params.p.push(v as u32); for w in bitvec[v * length..][..length].iter_ones() { - if !params.scca[w] { + if !params.scca.contains(&(w as u32)) { match params.preorders[w] { Preorder::Filled(pw) => loop { - let index = params.p.last_one().unwrap(); + let index = *params.p.last().unwrap(); match params.preorders[index as usize] { Preorder::Empty => unreachable!(), Preorder::Filled(current) => { if current > pw { - params.p.set(index, false); + params.p.pop(); } else { break; } @@ -243,15 +243,15 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { } } - if params.p.last_one() == Some(v) { - params.p.set(v, false); + if params.p.last() == Some(&(v as u32)) { + params.p.pop(); while let Some(node) = params.s.pop() { params .scc .matrix .set_row_col(params.scc.components, node as usize, true); - params.scca.set(node as usize, true); + params.scca.push(node); params.preorders[node as usize] = Preorder::Removed; if node as usize == v { break; From 13fc0f9a1e7b5c6c4fac052563b1cf6969e5375f Mon Sep 17 00:00:00 2001 From: Folkert Date: Fri, 6 May 2022 22:06:16 +0200 Subject: [PATCH 6/7] make params.p use a bitvec --- compiler/can/src/reference_matrix.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/can/src/reference_matrix.rs b/compiler/can/src/reference_matrix.rs index 3b7a2a6f11..092ca401d1 100644 --- a/compiler/can/src/reference_matrix.rs +++ b/compiler/can/src/reference_matrix.rs @@ -186,7 +186,7 @@ struct Params { p: Vec, s: Vec, scc: Sccs, - scca: Vec, + scca: BitVec, } impl Params { @@ -206,7 +206,7 @@ impl Params { matrix: ReferenceMatrix::new(length), components: 0, }, - scca: Vec::new(), + scca: BitVec::repeat(false, length), } } } @@ -220,7 +220,7 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { params.p.push(v as u32); for w in bitvec[v * length..][..length].iter_ones() { - if !params.scca.contains(&(w as u32)) { + if !params.scca[w] { match params.preorders[w] { Preorder::Filled(pw) => loop { let index = *params.p.last().unwrap(); @@ -251,7 +251,7 @@ fn recurse_onto(length: usize, bitvec: &BitVec, v: usize, params: &mut Params) { .scc .matrix .set_row_col(params.scc.components, node as usize, true); - params.scca.push(node); + params.scca.set(node as usize, true); params.preorders[node as usize] = Preorder::Removed; if node as usize == v { break; From 8a209334cc03acf0bfec5ff71d5878ff74ef3efc Mon Sep 17 00:00:00 2001 From: Folkert Date: Sat, 7 May 2022 00:33:27 +0200 Subject: [PATCH 7/7] use bitvec in the input for sccs --- compiler/can/src/def.rs | 29 +++++++++------------------- compiler/can/src/reference_matrix.rs | 16 ++++++--------- compiler/load_internal/src/file.rs | 2 +- 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/compiler/can/src/def.rs b/compiler/can/src/def.rs index cd7d5e2981..59b2c7c29d 100644 --- a/compiler/can/src/def.rs +++ b/compiler/can/src/def.rs @@ -192,17 +192,12 @@ fn sort_type_defs_before_introduction( } // find the strongly connected components and their relations - let nodes: Vec<_> = (0..capacity as u32).collect(); - - let mut output = Vec::with_capacity(capacity); - - for group in matrix.strongly_connected_components(&nodes).groups() { - for index in group.iter_ones() { - output.push(symbols[index]) - } - } - - output + matrix + .strongly_connected_components_all() + .groups() + .flat_map(|group| group.iter_ones()) + .map(|index| symbols[index]) + .collect() } #[inline(always)] @@ -790,14 +785,10 @@ pub(crate) fn sort_can_defs( }; } - let nodes: Vec<_> = (0..defs.len() as u32).collect(); - // We first perform SCC based on any reference, both variable usage and calls // considering both value definitions and function bodies. This will spot any // recursive relations between any 2 definitions. - let sccs = def_ordering - .references - .strongly_connected_components(&nodes); + let sccs = def_ordering.references.strongly_connected_components_all(); let mut declarations = Vec::new(); @@ -838,10 +829,9 @@ pub(crate) fn sort_can_defs( // boom = \{} -> boom {} // // In general we cannot spot faulty recursion (halting problem) so this is our best attempt - let nodes: Vec<_> = group.iter_ones().map(|v| v as u32).collect(); let direct_sccs = def_ordering .direct_references - .strongly_connected_components(&nodes); + .strongly_connected_components_subset(group); let declaration = if direct_sccs.groups().count() == 1 { // all defs are part of the same direct cycle, that is invalid! @@ -1571,8 +1561,7 @@ fn correct_mutual_recursive_type_alias<'a>( let mut solved_aliases = bitvec::vec::BitVec::::repeat(false, capacity); - let group: Vec<_> = (0u32..capacity as u32).collect(); - let sccs = matrix.strongly_connected_components(&group); + let sccs = matrix.strongly_connected_components_all(); // scratchpad to store aliases that are modified in the current iteration. // Only used when there is are more than one alias in a group. See below why diff --git a/compiler/can/src/reference_matrix.rs b/compiler/can/src/reference_matrix.rs index 092ca401d1..cd06528109 100644 --- a/compiler/can/src/reference_matrix.rs +++ b/compiler/can/src/reference_matrix.rs @@ -129,18 +129,14 @@ impl ReferenceMatrix { TopologicalSort::Groups { groups } } - /// Get the strongly-connected components of the set of input nodes. - pub fn strongly_connected_components(&self, nodes: &[u32]) -> Sccs { - let mut bitvec = BitVec::repeat(false, self.length); - - for value in nodes { - bitvec.set(*value as usize, true); - } - - self.strongly_connected_components_help(&bitvec) + /// Get the strongly-connected components all nodes in the matrix + pub fn strongly_connected_components_all(&self) -> Sccs { + let bitvec = BitVec::repeat(true, self.length); + self.strongly_connected_components_subset(&bitvec) } - fn strongly_connected_components_help(&self, nodes: &BitSlice) -> Sccs { + /// Get the strongly-connected components of a set of input nodes. + pub fn strongly_connected_components_subset(&self, nodes: &BitSlice) -> Sccs { let mut params = Params::new(self.length, nodes); 'outer: loop { diff --git a/compiler/load_internal/src/file.rs b/compiler/load_internal/src/file.rs index 8e210557b8..f97bf7d012 100644 --- a/compiler/load_internal/src/file.rs +++ b/compiler/load_internal/src/file.rs @@ -1159,7 +1159,7 @@ pub fn load<'a>( ) -> Result, LoadingProblem<'a>> { // When compiling to wasm, we cannot spawn extra threads // so we have a single-threaded implementation - if true || threading == Threading::Single || cfg!(target_family = "wasm") { + if threading == Threading::Single || cfg!(target_family = "wasm") { load_single_threaded( arena, load_start,