1use crate::lcnf::*;
6use std::collections::{HashMap, HashSet};
7
8use super::functions::*;
9use std::collections::VecDeque;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
13pub enum EscapeInfo {
14 NoEscape,
17 LocalEscape,
20 GlobalEscape,
23}
24impl EscapeInfo {
25 pub fn merge(self, other: EscapeInfo) -> EscapeInfo {
27 match (self, other) {
28 (EscapeInfo::GlobalEscape, _) | (_, EscapeInfo::GlobalEscape) => {
29 EscapeInfo::GlobalEscape
30 }
31 (EscapeInfo::LocalEscape, _) | (_, EscapeInfo::LocalEscape) => EscapeInfo::LocalEscape,
32 _ => EscapeInfo::NoEscape,
33 }
34 }
35 pub fn requires_heap(self) -> bool {
37 matches!(self, EscapeInfo::GlobalEscape)
38 }
39}
40#[allow(dead_code)]
41#[derive(Debug, Clone)]
42pub struct CCDominatorTree {
43 pub idom: Vec<Option<u32>>,
44 pub dom_children: Vec<Vec<u32>>,
45 pub dom_depth: Vec<u32>,
46}
47impl CCDominatorTree {
48 #[allow(dead_code)]
49 pub fn new(size: usize) -> Self {
50 CCDominatorTree {
51 idom: vec![None; size],
52 dom_children: vec![Vec::new(); size],
53 dom_depth: vec![0; size],
54 }
55 }
56 #[allow(dead_code)]
57 pub fn set_idom(&mut self, node: usize, idom: u32) {
58 self.idom[node] = Some(idom);
59 }
60 #[allow(dead_code)]
61 pub fn dominates(&self, a: usize, b: usize) -> bool {
62 if a == b {
63 return true;
64 }
65 let mut cur = b;
66 loop {
67 match self.idom[cur] {
68 Some(parent) if parent as usize == a => return true,
69 Some(parent) if parent as usize == cur => return false,
70 Some(parent) => cur = parent as usize,
71 None => return false,
72 }
73 }
74 }
75 #[allow(dead_code)]
76 pub fn depth(&self, node: usize) -> u32 {
77 self.dom_depth.get(node).copied().unwrap_or(0)
78 }
79}
80#[allow(dead_code)]
81#[derive(Debug, Clone)]
82pub struct CCAnalysisCache {
83 pub(super) entries: std::collections::HashMap<String, CCCacheEntry>,
84 pub(super) max_size: usize,
85 pub(super) hits: u64,
86 pub(super) misses: u64,
87}
88impl CCAnalysisCache {
89 #[allow(dead_code)]
90 pub fn new(max_size: usize) -> Self {
91 CCAnalysisCache {
92 entries: std::collections::HashMap::new(),
93 max_size,
94 hits: 0,
95 misses: 0,
96 }
97 }
98 #[allow(dead_code)]
99 pub fn get(&mut self, key: &str) -> Option<&CCCacheEntry> {
100 if self.entries.contains_key(key) {
101 self.hits += 1;
102 self.entries.get(key)
103 } else {
104 self.misses += 1;
105 None
106 }
107 }
108 #[allow(dead_code)]
109 pub fn insert(&mut self, key: String, data: Vec<u8>) {
110 if self.entries.len() >= self.max_size {
111 if let Some(oldest) = self.entries.keys().next().cloned() {
112 self.entries.remove(&oldest);
113 }
114 }
115 self.entries.insert(
116 key.clone(),
117 CCCacheEntry {
118 key,
119 data,
120 timestamp: 0,
121 valid: true,
122 },
123 );
124 }
125 #[allow(dead_code)]
126 pub fn invalidate(&mut self, key: &str) {
127 if let Some(entry) = self.entries.get_mut(key) {
128 entry.valid = false;
129 }
130 }
131 #[allow(dead_code)]
132 pub fn clear(&mut self) {
133 self.entries.clear();
134 }
135 #[allow(dead_code)]
136 pub fn hit_rate(&self) -> f64 {
137 let total = self.hits + self.misses;
138 if total == 0 {
139 return 0.0;
140 }
141 self.hits as f64 / total as f64
142 }
143 #[allow(dead_code)]
144 pub fn size(&self) -> usize {
145 self.entries.len()
146 }
147}
148#[allow(dead_code)]
150#[derive(Debug, Clone)]
151pub struct CCExtDomTree {
152 pub(super) idom: Vec<Option<usize>>,
153 pub(super) children: Vec<Vec<usize>>,
154 pub(super) depth: Vec<usize>,
155}
156impl CCExtDomTree {
157 #[allow(dead_code)]
158 pub fn new(n: usize) -> Self {
159 Self {
160 idom: vec![None; n],
161 children: vec![Vec::new(); n],
162 depth: vec![0; n],
163 }
164 }
165 #[allow(dead_code)]
166 pub fn set_idom(&mut self, node: usize, dom: usize) {
167 if node < self.idom.len() {
168 self.idom[node] = Some(dom);
169 if dom < self.children.len() {
170 self.children[dom].push(node);
171 }
172 self.depth[node] = if dom < self.depth.len() {
173 self.depth[dom] + 1
174 } else {
175 1
176 };
177 }
178 }
179 #[allow(dead_code)]
180 pub fn dominates(&self, a: usize, mut b: usize) -> bool {
181 if a == b {
182 return true;
183 }
184 let n = self.idom.len();
185 for _ in 0..n {
186 match self.idom.get(b).copied().flatten() {
187 None => return false,
188 Some(p) if p == a => return true,
189 Some(p) if p == b => return false,
190 Some(p) => b = p,
191 }
192 }
193 false
194 }
195 #[allow(dead_code)]
196 pub fn children_of(&self, n: usize) -> &[usize] {
197 self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
198 }
199 #[allow(dead_code)]
200 pub fn depth_of(&self, n: usize) -> usize {
201 self.depth.get(n).copied().unwrap_or(0)
202 }
203 #[allow(dead_code)]
204 pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
205 let n = self.idom.len();
206 for _ in 0..(2 * n) {
207 if a == b {
208 return a;
209 }
210 if self.depth_of(a) > self.depth_of(b) {
211 a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
212 } else {
213 b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
214 }
215 }
216 0
217 }
218}
219pub struct EscapeAnalysis {
221 pub(super) var_escape: HashMap<LcnfVarId, EscapeInfo>,
223 pub(super) fn_escape: HashMap<String, EscapeInfo>,
225 pub(super) returned_vars: HashSet<LcnfVarId>,
227 pub(super) externally_passed: HashSet<LcnfVarId>,
229 pub(super) stored_in_ctor: HashSet<LcnfVarId>,
231}
232impl EscapeAnalysis {
233 pub fn new() -> Self {
235 EscapeAnalysis {
236 var_escape: HashMap::new(),
237 fn_escape: HashMap::new(),
238 returned_vars: HashSet::new(),
239 externally_passed: HashSet::new(),
240 stored_in_ctor: HashSet::new(),
241 }
242 }
243 pub fn analyze(&mut self, module: &LcnfModule) -> HashMap<String, EscapeInfo> {
245 for decl in &module.fun_decls {
246 self.analyze_function(decl);
247 }
248 self.fn_escape.clone()
249 }
250 pub(super) fn analyze_function(&mut self, decl: &LcnfFunDecl) {
252 for param in &decl.params {
253 self.var_escape.insert(param.id, EscapeInfo::LocalEscape);
254 }
255 self.analyze_expr(&decl.body, false);
256 let fn_escape = if self.returned_vars.iter().any(|v| {
257 self.var_escape
258 .get(v)
259 .copied()
260 .unwrap_or(EscapeInfo::NoEscape)
261 == EscapeInfo::GlobalEscape
262 }) {
263 EscapeInfo::GlobalEscape
264 } else {
265 EscapeInfo::NoEscape
266 };
267 self.fn_escape.insert(decl.name.clone(), fn_escape);
268 }
269 pub(super) fn analyze_expr(&mut self, expr: &LcnfExpr, _is_tail_position: bool) {
271 match expr {
272 LcnfExpr::Let {
273 id, value, body, ..
274 } => {
275 let escape = self.analyze_let_value(value);
276 self.var_escape.insert(*id, escape);
277 self.analyze_expr(body, _is_tail_position);
278 }
279 LcnfExpr::Case {
280 scrutinee,
281 alts,
282 default,
283 ..
284 } => {
285 self.mark_read(*scrutinee);
286 for alt in alts {
287 for param in &alt.params {
288 self.var_escape.insert(param.id, EscapeInfo::LocalEscape);
289 }
290 self.analyze_expr(&alt.body, _is_tail_position);
291 }
292 if let Some(def) = default {
293 self.analyze_expr(def, _is_tail_position);
294 }
295 }
296 LcnfExpr::Return(arg) => {
297 if let LcnfArg::Var(v) = arg {
298 self.returned_vars.insert(*v);
299 self.mark_escape(*v, EscapeInfo::GlobalEscape);
300 }
301 }
302 LcnfExpr::TailCall(func, args) => {
303 if let LcnfArg::Var(v) = func {
304 self.mark_escape(*v, EscapeInfo::GlobalEscape);
305 }
306 for arg in args {
307 if let LcnfArg::Var(v) = arg {
308 self.externally_passed.insert(*v);
309 self.mark_escape(*v, EscapeInfo::GlobalEscape);
310 }
311 }
312 }
313 LcnfExpr::Unreachable => {}
314 }
315 }
316 pub(super) fn analyze_let_value(&mut self, value: &LcnfLetValue) -> EscapeInfo {
318 match value {
319 LcnfLetValue::App(func, args) => {
320 if let LcnfArg::Var(v) = func {
321 self.mark_read(*v);
322 }
323 for arg in args {
324 if let LcnfArg::Var(v) = arg {
325 self.externally_passed.insert(*v);
326 self.mark_escape(*v, EscapeInfo::GlobalEscape);
327 }
328 }
329 EscapeInfo::LocalEscape
330 }
331 LcnfLetValue::Ctor(_, _, args) => {
332 for arg in args {
333 if let LcnfArg::Var(v) = arg {
334 self.stored_in_ctor.insert(*v);
335 self.mark_escape(*v, EscapeInfo::GlobalEscape);
336 }
337 }
338 EscapeInfo::LocalEscape
339 }
340 LcnfLetValue::Proj(_, _, var) => {
341 self.mark_read(*var);
342 EscapeInfo::LocalEscape
343 }
344 LcnfLetValue::FVar(var) => {
345 self.mark_read(*var);
346 self.var_escape
347 .get(var)
348 .copied()
349 .unwrap_or(EscapeInfo::NoEscape)
350 }
351 LcnfLetValue::Lit(_)
352 | LcnfLetValue::Erased
353 | LcnfLetValue::Reset(_)
354 | LcnfLetValue::Reuse(_, _, _, _) => EscapeInfo::NoEscape,
355 }
356 }
357 pub(super) fn mark_read(&mut self, var: LcnfVarId) {
359 self.var_escape.entry(var).or_insert(EscapeInfo::NoEscape);
360 }
361 pub(super) fn mark_escape(&mut self, var: LcnfVarId, escape: EscapeInfo) {
363 let current = self
364 .var_escape
365 .get(&var)
366 .copied()
367 .unwrap_or(EscapeInfo::NoEscape);
368 self.var_escape.insert(var, current.merge(escape));
369 }
370 pub fn get_var_escape(&self, var: LcnfVarId) -> EscapeInfo {
372 self.var_escape
373 .get(&var)
374 .copied()
375 .unwrap_or(EscapeInfo::NoEscape)
376 }
377 pub fn get_fn_escape(&self, name: &str) -> EscapeInfo {
379 self.fn_escape
380 .get(name)
381 .copied()
382 .unwrap_or(EscapeInfo::NoEscape)
383 }
384}
385#[allow(dead_code)]
387#[derive(Debug, Clone, Default)]
388pub struct CCExtConstFolder {
389 pub(super) folds: usize,
390 pub(super) failures: usize,
391 pub(super) enabled: bool,
392}
393impl CCExtConstFolder {
394 #[allow(dead_code)]
395 pub fn new() -> Self {
396 Self {
397 folds: 0,
398 failures: 0,
399 enabled: true,
400 }
401 }
402 #[allow(dead_code)]
403 pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
404 self.folds += 1;
405 a.checked_add(b)
406 }
407 #[allow(dead_code)]
408 pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
409 self.folds += 1;
410 a.checked_sub(b)
411 }
412 #[allow(dead_code)]
413 pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
414 self.folds += 1;
415 a.checked_mul(b)
416 }
417 #[allow(dead_code)]
418 pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
419 if b == 0 {
420 self.failures += 1;
421 None
422 } else {
423 self.folds += 1;
424 a.checked_div(b)
425 }
426 }
427 #[allow(dead_code)]
428 pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
429 if b == 0 {
430 self.failures += 1;
431 None
432 } else {
433 self.folds += 1;
434 a.checked_rem(b)
435 }
436 }
437 #[allow(dead_code)]
438 pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
439 self.folds += 1;
440 a.checked_neg()
441 }
442 #[allow(dead_code)]
443 pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
444 if s >= 64 {
445 self.failures += 1;
446 None
447 } else {
448 self.folds += 1;
449 a.checked_shl(s)
450 }
451 }
452 #[allow(dead_code)]
453 pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
454 if s >= 64 {
455 self.failures += 1;
456 None
457 } else {
458 self.folds += 1;
459 a.checked_shr(s)
460 }
461 }
462 #[allow(dead_code)]
463 pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
464 self.folds += 1;
465 a & b
466 }
467 #[allow(dead_code)]
468 pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
469 self.folds += 1;
470 a | b
471 }
472 #[allow(dead_code)]
473 pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
474 self.folds += 1;
475 a ^ b
476 }
477 #[allow(dead_code)]
478 pub fn not_i64(&mut self, a: i64) -> i64 {
479 self.folds += 1;
480 !a
481 }
482 #[allow(dead_code)]
483 pub fn fold_count(&self) -> usize {
484 self.folds
485 }
486 #[allow(dead_code)]
487 pub fn failure_count(&self) -> usize {
488 self.failures
489 }
490 #[allow(dead_code)]
491 pub fn enable(&mut self) {
492 self.enabled = true;
493 }
494 #[allow(dead_code)]
495 pub fn disable(&mut self) {
496 self.enabled = false;
497 }
498 #[allow(dead_code)]
499 pub fn is_enabled(&self) -> bool {
500 self.enabled
501 }
502}
503#[allow(dead_code)]
505#[derive(Debug, Clone, Default)]
506pub struct CCX2ConstFolder {
507 pub(super) folds: usize,
508 pub(super) failures: usize,
509 pub(super) enabled: bool,
510}
511impl CCX2ConstFolder {
512 #[allow(dead_code)]
513 pub fn new() -> Self {
514 Self {
515 folds: 0,
516 failures: 0,
517 enabled: true,
518 }
519 }
520 #[allow(dead_code)]
521 pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
522 self.folds += 1;
523 a.checked_add(b)
524 }
525 #[allow(dead_code)]
526 pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
527 self.folds += 1;
528 a.checked_sub(b)
529 }
530 #[allow(dead_code)]
531 pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
532 self.folds += 1;
533 a.checked_mul(b)
534 }
535 #[allow(dead_code)]
536 pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
537 if b == 0 {
538 self.failures += 1;
539 None
540 } else {
541 self.folds += 1;
542 a.checked_div(b)
543 }
544 }
545 #[allow(dead_code)]
546 pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
547 if b == 0 {
548 self.failures += 1;
549 None
550 } else {
551 self.folds += 1;
552 a.checked_rem(b)
553 }
554 }
555 #[allow(dead_code)]
556 pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
557 self.folds += 1;
558 a.checked_neg()
559 }
560 #[allow(dead_code)]
561 pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
562 if s >= 64 {
563 self.failures += 1;
564 None
565 } else {
566 self.folds += 1;
567 a.checked_shl(s)
568 }
569 }
570 #[allow(dead_code)]
571 pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
572 if s >= 64 {
573 self.failures += 1;
574 None
575 } else {
576 self.folds += 1;
577 a.checked_shr(s)
578 }
579 }
580 #[allow(dead_code)]
581 pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
582 self.folds += 1;
583 a & b
584 }
585 #[allow(dead_code)]
586 pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
587 self.folds += 1;
588 a | b
589 }
590 #[allow(dead_code)]
591 pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
592 self.folds += 1;
593 a ^ b
594 }
595 #[allow(dead_code)]
596 pub fn not_i64(&mut self, a: i64) -> i64 {
597 self.folds += 1;
598 !a
599 }
600 #[allow(dead_code)]
601 pub fn fold_count(&self) -> usize {
602 self.folds
603 }
604 #[allow(dead_code)]
605 pub fn failure_count(&self) -> usize {
606 self.failures
607 }
608 #[allow(dead_code)]
609 pub fn enable(&mut self) {
610 self.enabled = true;
611 }
612 #[allow(dead_code)]
613 pub fn disable(&mut self) {
614 self.enabled = false;
615 }
616 #[allow(dead_code)]
617 pub fn is_enabled(&self) -> bool {
618 self.enabled
619 }
620}
621#[allow(dead_code)]
623#[derive(Debug, Clone, Default)]
624pub struct CCExtPassStats {
625 pub iterations: usize,
626 pub changed: bool,
627 pub nodes_visited: usize,
628 pub nodes_modified: usize,
629 pub time_ms: u64,
630 pub memory_bytes: usize,
631 pub errors: usize,
632}
633impl CCExtPassStats {
634 #[allow(dead_code)]
635 pub fn new() -> Self {
636 Self::default()
637 }
638 #[allow(dead_code)]
639 pub fn visit(&mut self) {
640 self.nodes_visited += 1;
641 }
642 #[allow(dead_code)]
643 pub fn modify(&mut self) {
644 self.nodes_modified += 1;
645 self.changed = true;
646 }
647 #[allow(dead_code)]
648 pub fn iterate(&mut self) {
649 self.iterations += 1;
650 }
651 #[allow(dead_code)]
652 pub fn error(&mut self) {
653 self.errors += 1;
654 }
655 #[allow(dead_code)]
656 pub fn efficiency(&self) -> f64 {
657 if self.nodes_visited == 0 {
658 0.0
659 } else {
660 self.nodes_modified as f64 / self.nodes_visited as f64
661 }
662 }
663 #[allow(dead_code)]
664 pub fn merge(&mut self, o: &CCExtPassStats) {
665 self.iterations += o.iterations;
666 self.changed |= o.changed;
667 self.nodes_visited += o.nodes_visited;
668 self.nodes_modified += o.nodes_modified;
669 self.time_ms += o.time_ms;
670 self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
671 self.errors += o.errors;
672 }
673}
674#[allow(dead_code)]
676#[derive(Debug, Clone)]
677pub struct CCExtDepGraph {
678 pub(super) n: usize,
679 pub(super) adj: Vec<Vec<usize>>,
680 pub(super) rev: Vec<Vec<usize>>,
681 pub(super) edge_count: usize,
682}
683impl CCExtDepGraph {
684 #[allow(dead_code)]
685 pub fn new(n: usize) -> Self {
686 Self {
687 n,
688 adj: vec![Vec::new(); n],
689 rev: vec![Vec::new(); n],
690 edge_count: 0,
691 }
692 }
693 #[allow(dead_code)]
694 pub fn add_edge(&mut self, from: usize, to: usize) {
695 if from < self.n && to < self.n {
696 if !self.adj[from].contains(&to) {
697 self.adj[from].push(to);
698 self.rev[to].push(from);
699 self.edge_count += 1;
700 }
701 }
702 }
703 #[allow(dead_code)]
704 pub fn succs(&self, n: usize) -> &[usize] {
705 self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
706 }
707 #[allow(dead_code)]
708 pub fn preds(&self, n: usize) -> &[usize] {
709 self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
710 }
711 #[allow(dead_code)]
712 pub fn topo_sort(&self) -> Option<Vec<usize>> {
713 let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
714 let mut q: std::collections::VecDeque<usize> =
715 (0..self.n).filter(|&i| deg[i] == 0).collect();
716 let mut out = Vec::with_capacity(self.n);
717 while let Some(u) = q.pop_front() {
718 out.push(u);
719 for &v in &self.adj[u] {
720 deg[v] -= 1;
721 if deg[v] == 0 {
722 q.push_back(v);
723 }
724 }
725 }
726 if out.len() == self.n {
727 Some(out)
728 } else {
729 None
730 }
731 }
732 #[allow(dead_code)]
733 pub fn has_cycle(&self) -> bool {
734 self.topo_sort().is_none()
735 }
736 #[allow(dead_code)]
737 pub fn reachable(&self, start: usize) -> Vec<usize> {
738 let mut vis = vec![false; self.n];
739 let mut stk = vec![start];
740 let mut out = Vec::new();
741 while let Some(u) = stk.pop() {
742 if u < self.n && !vis[u] {
743 vis[u] = true;
744 out.push(u);
745 for &v in &self.adj[u] {
746 if !vis[v] {
747 stk.push(v);
748 }
749 }
750 }
751 }
752 out
753 }
754 #[allow(dead_code)]
755 pub fn scc(&self) -> Vec<Vec<usize>> {
756 let mut visited = vec![false; self.n];
757 let mut order = Vec::new();
758 for i in 0..self.n {
759 if !visited[i] {
760 let mut stk = vec![(i, 0usize)];
761 while let Some((u, idx)) = stk.last_mut() {
762 if !visited[*u] {
763 visited[*u] = true;
764 }
765 if *idx < self.adj[*u].len() {
766 let v = self.adj[*u][*idx];
767 *idx += 1;
768 if !visited[v] {
769 stk.push((v, 0));
770 }
771 } else {
772 order.push(*u);
773 stk.pop();
774 }
775 }
776 }
777 }
778 let mut comp = vec![usize::MAX; self.n];
779 let mut components: Vec<Vec<usize>> = Vec::new();
780 for &start in order.iter().rev() {
781 if comp[start] == usize::MAX {
782 let cid = components.len();
783 let mut component = Vec::new();
784 let mut stk = vec![start];
785 while let Some(u) = stk.pop() {
786 if comp[u] == usize::MAX {
787 comp[u] = cid;
788 component.push(u);
789 for &v in &self.rev[u] {
790 if comp[v] == usize::MAX {
791 stk.push(v);
792 }
793 }
794 }
795 }
796 components.push(component);
797 }
798 }
799 components
800 }
801 #[allow(dead_code)]
802 pub fn node_count(&self) -> usize {
803 self.n
804 }
805 #[allow(dead_code)]
806 pub fn edge_count(&self) -> usize {
807 self.edge_count
808 }
809}
810#[allow(dead_code)]
812#[derive(Debug)]
813pub struct CCExtCache {
814 pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
815 pub(super) cap: usize,
816 pub(super) total_hits: u64,
817 pub(super) total_misses: u64,
818}
819impl CCExtCache {
820 #[allow(dead_code)]
821 pub fn new(cap: usize) -> Self {
822 Self {
823 entries: Vec::new(),
824 cap,
825 total_hits: 0,
826 total_misses: 0,
827 }
828 }
829 #[allow(dead_code)]
830 pub fn get(&mut self, key: u64) -> Option<&[u8]> {
831 for e in self.entries.iter_mut() {
832 if e.0 == key && e.2 {
833 e.3 += 1;
834 self.total_hits += 1;
835 return Some(&e.1);
836 }
837 }
838 self.total_misses += 1;
839 None
840 }
841 #[allow(dead_code)]
842 pub fn put(&mut self, key: u64, data: Vec<u8>) {
843 if self.entries.len() >= self.cap {
844 self.entries.retain(|e| e.2);
845 if self.entries.len() >= self.cap {
846 self.entries.remove(0);
847 }
848 }
849 self.entries.push((key, data, true, 0));
850 }
851 #[allow(dead_code)]
852 pub fn invalidate(&mut self) {
853 for e in self.entries.iter_mut() {
854 e.2 = false;
855 }
856 }
857 #[allow(dead_code)]
858 pub fn hit_rate(&self) -> f64 {
859 let t = self.total_hits + self.total_misses;
860 if t == 0 {
861 0.0
862 } else {
863 self.total_hits as f64 / t as f64
864 }
865 }
866 #[allow(dead_code)]
867 pub fn live_count(&self) -> usize {
868 self.entries.iter().filter(|e| e.2).count()
869 }
870}
871#[allow(dead_code)]
873#[derive(Debug, Clone, PartialEq, Eq, Hash)]
874pub enum CCX2PassPhase {
875 Early,
876 Middle,
877 Late,
878 Finalize,
879}
880impl CCX2PassPhase {
881 #[allow(dead_code)]
882 pub fn is_early(&self) -> bool {
883 matches!(self, Self::Early)
884 }
885 #[allow(dead_code)]
886 pub fn is_middle(&self) -> bool {
887 matches!(self, Self::Middle)
888 }
889 #[allow(dead_code)]
890 pub fn is_late(&self) -> bool {
891 matches!(self, Self::Late)
892 }
893 #[allow(dead_code)]
894 pub fn is_finalize(&self) -> bool {
895 matches!(self, Self::Finalize)
896 }
897 #[allow(dead_code)]
898 pub fn order(&self) -> u32 {
899 match self {
900 Self::Early => 0,
901 Self::Middle => 1,
902 Self::Late => 2,
903 Self::Finalize => 3,
904 }
905 }
906 #[allow(dead_code)]
907 pub fn from_order(n: u32) -> Option<Self> {
908 match n {
909 0 => Some(Self::Early),
910 1 => Some(Self::Middle),
911 2 => Some(Self::Late),
912 3 => Some(Self::Finalize),
913 _ => None,
914 }
915 }
916}
917#[allow(dead_code)]
918pub struct CCConstantFoldingHelper;
919impl CCConstantFoldingHelper {
920 #[allow(dead_code)]
921 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
922 a.checked_add(b)
923 }
924 #[allow(dead_code)]
925 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
926 a.checked_sub(b)
927 }
928 #[allow(dead_code)]
929 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
930 a.checked_mul(b)
931 }
932 #[allow(dead_code)]
933 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
934 if b == 0 {
935 None
936 } else {
937 a.checked_div(b)
938 }
939 }
940 #[allow(dead_code)]
941 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
942 a + b
943 }
944 #[allow(dead_code)]
945 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
946 a * b
947 }
948 #[allow(dead_code)]
949 pub fn fold_neg_i64(a: i64) -> Option<i64> {
950 a.checked_neg()
951 }
952 #[allow(dead_code)]
953 pub fn fold_not_bool(a: bool) -> bool {
954 !a
955 }
956 #[allow(dead_code)]
957 pub fn fold_and_bool(a: bool, b: bool) -> bool {
958 a && b
959 }
960 #[allow(dead_code)]
961 pub fn fold_or_bool(a: bool, b: bool) -> bool {
962 a || b
963 }
964 #[allow(dead_code)]
965 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
966 a.checked_shl(b)
967 }
968 #[allow(dead_code)]
969 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
970 a.checked_shr(b)
971 }
972 #[allow(dead_code)]
973 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
974 if b == 0 {
975 None
976 } else {
977 Some(a % b)
978 }
979 }
980 #[allow(dead_code)]
981 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
982 a & b
983 }
984 #[allow(dead_code)]
985 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
986 a | b
987 }
988 #[allow(dead_code)]
989 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
990 a ^ b
991 }
992 #[allow(dead_code)]
993 pub fn fold_bitnot_i64(a: i64) -> i64 {
994 !a
995 }
996}
997#[allow(dead_code)]
999#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1000pub enum CCExtPassPhase {
1001 Early,
1002 Middle,
1003 Late,
1004 Finalize,
1005}
1006impl CCExtPassPhase {
1007 #[allow(dead_code)]
1008 pub fn is_early(&self) -> bool {
1009 matches!(self, Self::Early)
1010 }
1011 #[allow(dead_code)]
1012 pub fn is_middle(&self) -> bool {
1013 matches!(self, Self::Middle)
1014 }
1015 #[allow(dead_code)]
1016 pub fn is_late(&self) -> bool {
1017 matches!(self, Self::Late)
1018 }
1019 #[allow(dead_code)]
1020 pub fn is_finalize(&self) -> bool {
1021 matches!(self, Self::Finalize)
1022 }
1023 #[allow(dead_code)]
1024 pub fn order(&self) -> u32 {
1025 match self {
1026 Self::Early => 0,
1027 Self::Middle => 1,
1028 Self::Late => 2,
1029 Self::Finalize => 3,
1030 }
1031 }
1032 #[allow(dead_code)]
1033 pub fn from_order(n: u32) -> Option<Self> {
1034 match n {
1035 0 => Some(Self::Early),
1036 1 => Some(Self::Middle),
1037 2 => Some(Self::Late),
1038 3 => Some(Self::Finalize),
1039 _ => None,
1040 }
1041 }
1042}
1043#[allow(dead_code)]
1045#[derive(Debug, Clone)]
1046pub struct CCExtPassConfig {
1047 pub name: String,
1048 pub phase: CCExtPassPhase,
1049 pub enabled: bool,
1050 pub max_iterations: usize,
1051 pub debug: u32,
1052 pub timeout_ms: Option<u64>,
1053}
1054impl CCExtPassConfig {
1055 #[allow(dead_code)]
1056 pub fn new(name: impl Into<String>) -> Self {
1057 Self {
1058 name: name.into(),
1059 phase: CCExtPassPhase::Middle,
1060 enabled: true,
1061 max_iterations: 100,
1062 debug: 0,
1063 timeout_ms: None,
1064 }
1065 }
1066 #[allow(dead_code)]
1067 pub fn with_phase(mut self, phase: CCExtPassPhase) -> Self {
1068 self.phase = phase;
1069 self
1070 }
1071 #[allow(dead_code)]
1072 pub fn with_max_iter(mut self, n: usize) -> Self {
1073 self.max_iterations = n;
1074 self
1075 }
1076 #[allow(dead_code)]
1077 pub fn with_debug(mut self, d: u32) -> Self {
1078 self.debug = d;
1079 self
1080 }
1081 #[allow(dead_code)]
1082 pub fn disabled(mut self) -> Self {
1083 self.enabled = false;
1084 self
1085 }
1086 #[allow(dead_code)]
1087 pub fn with_timeout(mut self, ms: u64) -> Self {
1088 self.timeout_ms = Some(ms);
1089 self
1090 }
1091 #[allow(dead_code)]
1092 pub fn is_debug_enabled(&self) -> bool {
1093 self.debug > 0
1094 }
1095}
1096#[allow(dead_code)]
1098#[derive(Debug, Default)]
1099pub struct CCX2PassRegistry {
1100 pub(super) configs: Vec<CCX2PassConfig>,
1101 pub(super) stats: Vec<CCX2PassStats>,
1102}
1103impl CCX2PassRegistry {
1104 #[allow(dead_code)]
1105 pub fn new() -> Self {
1106 Self::default()
1107 }
1108 #[allow(dead_code)]
1109 pub fn register(&mut self, c: CCX2PassConfig) {
1110 self.stats.push(CCX2PassStats::new());
1111 self.configs.push(c);
1112 }
1113 #[allow(dead_code)]
1114 pub fn len(&self) -> usize {
1115 self.configs.len()
1116 }
1117 #[allow(dead_code)]
1118 pub fn is_empty(&self) -> bool {
1119 self.configs.is_empty()
1120 }
1121 #[allow(dead_code)]
1122 pub fn get(&self, i: usize) -> Option<&CCX2PassConfig> {
1123 self.configs.get(i)
1124 }
1125 #[allow(dead_code)]
1126 pub fn get_stats(&self, i: usize) -> Option<&CCX2PassStats> {
1127 self.stats.get(i)
1128 }
1129 #[allow(dead_code)]
1130 pub fn enabled_passes(&self) -> Vec<&CCX2PassConfig> {
1131 self.configs.iter().filter(|c| c.enabled).collect()
1132 }
1133 #[allow(dead_code)]
1134 pub fn passes_in_phase(&self, ph: &CCX2PassPhase) -> Vec<&CCX2PassConfig> {
1135 self.configs
1136 .iter()
1137 .filter(|c| c.enabled && &c.phase == ph)
1138 .collect()
1139 }
1140 #[allow(dead_code)]
1141 pub fn total_nodes_visited(&self) -> usize {
1142 self.stats.iter().map(|s| s.nodes_visited).sum()
1143 }
1144 #[allow(dead_code)]
1145 pub fn any_changed(&self) -> bool {
1146 self.stats.iter().any(|s| s.changed)
1147 }
1148}
1149#[allow(dead_code)]
1150#[derive(Debug, Clone, PartialEq)]
1151pub enum CCPassPhase {
1152 Analysis,
1153 Transformation,
1154 Verification,
1155 Cleanup,
1156}
1157impl CCPassPhase {
1158 #[allow(dead_code)]
1159 pub fn name(&self) -> &str {
1160 match self {
1161 CCPassPhase::Analysis => "analysis",
1162 CCPassPhase::Transformation => "transformation",
1163 CCPassPhase::Verification => "verification",
1164 CCPassPhase::Cleanup => "cleanup",
1165 }
1166 }
1167 #[allow(dead_code)]
1168 pub fn is_modifying(&self) -> bool {
1169 matches!(self, CCPassPhase::Transformation | CCPassPhase::Cleanup)
1170 }
1171}
1172#[allow(dead_code)]
1173#[derive(Debug, Clone)]
1174pub struct CCPassConfig {
1175 pub phase: CCPassPhase,
1176 pub enabled: bool,
1177 pub max_iterations: u32,
1178 pub debug_output: bool,
1179 pub pass_name: String,
1180}
1181impl CCPassConfig {
1182 #[allow(dead_code)]
1183 pub fn new(name: impl Into<String>, phase: CCPassPhase) -> Self {
1184 CCPassConfig {
1185 phase,
1186 enabled: true,
1187 max_iterations: 10,
1188 debug_output: false,
1189 pass_name: name.into(),
1190 }
1191 }
1192 #[allow(dead_code)]
1193 pub fn disabled(mut self) -> Self {
1194 self.enabled = false;
1195 self
1196 }
1197 #[allow(dead_code)]
1198 pub fn with_debug(mut self) -> Self {
1199 self.debug_output = true;
1200 self
1201 }
1202 #[allow(dead_code)]
1203 pub fn max_iter(mut self, n: u32) -> Self {
1204 self.max_iterations = n;
1205 self
1206 }
1207}
1208#[allow(dead_code)]
1209#[derive(Debug, Clone)]
1210pub struct CCDepGraph {
1211 pub(super) nodes: Vec<u32>,
1212 pub(super) edges: Vec<(u32, u32)>,
1213}
1214impl CCDepGraph {
1215 #[allow(dead_code)]
1216 pub fn new() -> Self {
1217 CCDepGraph {
1218 nodes: Vec::new(),
1219 edges: Vec::new(),
1220 }
1221 }
1222 #[allow(dead_code)]
1223 pub fn add_node(&mut self, id: u32) {
1224 if !self.nodes.contains(&id) {
1225 self.nodes.push(id);
1226 }
1227 }
1228 #[allow(dead_code)]
1229 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
1230 self.add_node(dep);
1231 self.add_node(dependent);
1232 self.edges.push((dep, dependent));
1233 }
1234 #[allow(dead_code)]
1235 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
1236 self.edges
1237 .iter()
1238 .filter(|(d, _)| *d == node)
1239 .map(|(_, dep)| *dep)
1240 .collect()
1241 }
1242 #[allow(dead_code)]
1243 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
1244 self.edges
1245 .iter()
1246 .filter(|(_, dep)| *dep == node)
1247 .map(|(d, _)| *d)
1248 .collect()
1249 }
1250 #[allow(dead_code)]
1251 pub fn topological_sort(&self) -> Vec<u32> {
1252 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
1253 for &n in &self.nodes {
1254 in_degree.insert(n, 0);
1255 }
1256 for (_, dep) in &self.edges {
1257 *in_degree.entry(*dep).or_insert(0) += 1;
1258 }
1259 let mut queue: std::collections::VecDeque<u32> = self
1260 .nodes
1261 .iter()
1262 .filter(|&&n| in_degree[&n] == 0)
1263 .copied()
1264 .collect();
1265 let mut result = Vec::new();
1266 while let Some(node) = queue.pop_front() {
1267 result.push(node);
1268 for dep in self.dependents_of(node) {
1269 let cnt = in_degree.entry(dep).or_insert(0);
1270 *cnt = cnt.saturating_sub(1);
1271 if *cnt == 0 {
1272 queue.push_back(dep);
1273 }
1274 }
1275 }
1276 result
1277 }
1278 #[allow(dead_code)]
1279 pub fn has_cycle(&self) -> bool {
1280 self.topological_sort().len() < self.nodes.len()
1281 }
1282}
1283#[allow(dead_code)]
1284pub struct CCPassRegistry {
1285 pub(super) configs: Vec<CCPassConfig>,
1286 pub(super) stats: std::collections::HashMap<String, CCPassStats>,
1287}
1288impl CCPassRegistry {
1289 #[allow(dead_code)]
1290 pub fn new() -> Self {
1291 CCPassRegistry {
1292 configs: Vec::new(),
1293 stats: std::collections::HashMap::new(),
1294 }
1295 }
1296 #[allow(dead_code)]
1297 pub fn register(&mut self, config: CCPassConfig) {
1298 self.stats
1299 .insert(config.pass_name.clone(), CCPassStats::new());
1300 self.configs.push(config);
1301 }
1302 #[allow(dead_code)]
1303 pub fn enabled_passes(&self) -> Vec<&CCPassConfig> {
1304 self.configs.iter().filter(|c| c.enabled).collect()
1305 }
1306 #[allow(dead_code)]
1307 pub fn get_stats(&self, name: &str) -> Option<&CCPassStats> {
1308 self.stats.get(name)
1309 }
1310 #[allow(dead_code)]
1311 pub fn total_passes(&self) -> usize {
1312 self.configs.len()
1313 }
1314 #[allow(dead_code)]
1315 pub fn enabled_count(&self) -> usize {
1316 self.enabled_passes().len()
1317 }
1318 #[allow(dead_code)]
1319 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
1320 if let Some(stats) = self.stats.get_mut(name) {
1321 stats.record_run(changes, time_ms, iter);
1322 }
1323 }
1324}
1325#[allow(dead_code)]
1326#[derive(Debug, Clone)]
1327pub struct CCCacheEntry {
1328 pub key: String,
1329 pub data: Vec<u8>,
1330 pub timestamp: u64,
1331 pub valid: bool,
1332}
1333#[derive(Debug, Clone, Default)]
1335pub struct ClosureConvertStats {
1336 pub closures_converted: usize,
1338 pub helpers_lifted: usize,
1340 pub defunctionalized: usize,
1342 pub stack_allocated: usize,
1344 pub heap_allocated: usize,
1346 pub closures_merged: usize,
1348}
1349pub struct ClosureConverter {
1354 pub(super) config: ClosureConvertConfig,
1355 pub(super) stats: ClosureConvertStats,
1356 pub(super) escape_info: HashMap<LcnfVarId, EscapeInfo>,
1358 pub(super) closure_infos: HashMap<LcnfVarId, ClosureInfo>,
1360 pub(super) lifted_helpers: Vec<LcnfFunDecl>,
1362 pub(super) next_var: u64,
1364 pub(super) name_counter: usize,
1366 pub(super) known_functions: HashSet<String>,
1368}
1369impl ClosureConverter {
1370 pub fn new(config: ClosureConvertConfig) -> Self {
1372 ClosureConverter {
1373 config,
1374 stats: ClosureConvertStats::default(),
1375 escape_info: HashMap::new(),
1376 closure_infos: HashMap::new(),
1377 lifted_helpers: Vec::new(),
1378 next_var: 10000,
1379 name_counter: 0,
1380 known_functions: HashSet::new(),
1381 }
1382 }
1383 pub fn default_converter() -> Self {
1385 Self::new(ClosureConvertConfig::default())
1386 }
1387 pub(super) fn fresh_var(&mut self) -> LcnfVarId {
1389 let id = LcnfVarId(self.next_var);
1390 self.next_var += 1;
1391 id
1392 }
1393 pub(super) fn fresh_name(&mut self, base: &str) -> String {
1395 let name = format!("{}_closure_{}", base, self.name_counter);
1396 self.name_counter += 1;
1397 name
1398 }
1399 pub fn convert_module(&mut self, module: &mut LcnfModule) {
1401 let mut escape = EscapeAnalysis::new();
1402 escape.analyze(module);
1403 self.escape_info = escape.var_escape.clone();
1404 for decl in &module.fun_decls {
1405 self.known_functions.insert(decl.name.clone());
1406 }
1407 let mut new_decls = Vec::new();
1408 for decl in &module.fun_decls {
1409 let (converted, helpers) = self.convert_fun_decl(decl);
1410 new_decls.push(converted);
1411 new_decls.extend(helpers);
1412 }
1413 new_decls.append(&mut self.lifted_helpers);
1414 module.fun_decls = new_decls;
1415 }
1416 pub fn convert_fun_decl(&mut self, decl: &LcnfFunDecl) -> (LcnfFunDecl, Vec<LcnfFunDecl>) {
1421 let mut helpers = Vec::new();
1422 let bound: HashSet<LcnfVarId> = decl.params.iter().map(|p| p.id).collect();
1423 let _body_free = compute_free_vars(&decl.body, &bound);
1424 let new_body = self.convert_expr(&decl.body, &decl.name, &mut helpers);
1425 let converted = LcnfFunDecl {
1426 name: decl.name.clone(),
1427 original_name: decl.original_name.clone(),
1428 params: decl.params.clone(),
1429 ret_type: decl.ret_type.clone(),
1430 body: new_body,
1431 is_recursive: decl.is_recursive,
1432 is_lifted: decl.is_lifted,
1433 inline_cost: decl.inline_cost,
1434 };
1435 self.stats.closures_converted += helpers.len();
1436 (converted, helpers)
1437 }
1438 pub(super) fn convert_expr(
1440 &mut self,
1441 expr: &LcnfExpr,
1442 parent_fn: &str,
1443 helpers: &mut Vec<LcnfFunDecl>,
1444 ) -> LcnfExpr {
1445 match expr {
1446 LcnfExpr::Let {
1447 id,
1448 name,
1449 ty,
1450 value,
1451 body,
1452 } => {
1453 let new_value = self.convert_let_value(value, parent_fn, helpers);
1454 let new_body = self.convert_expr(body, parent_fn, helpers);
1455 LcnfExpr::Let {
1456 id: *id,
1457 name: name.clone(),
1458 ty: ty.clone(),
1459 value: new_value,
1460 body: Box::new(new_body),
1461 }
1462 }
1463 LcnfExpr::Case {
1464 scrutinee,
1465 scrutinee_ty,
1466 alts,
1467 default,
1468 } => {
1469 let new_alts: Vec<LcnfAlt> = alts
1470 .iter()
1471 .map(|alt| LcnfAlt {
1472 ctor_name: alt.ctor_name.clone(),
1473 ctor_tag: alt.ctor_tag,
1474 params: alt.params.clone(),
1475 body: self.convert_expr(&alt.body, parent_fn, helpers),
1476 })
1477 .collect();
1478 let new_default = default
1479 .as_ref()
1480 .map(|d| Box::new(self.convert_expr(d, parent_fn, helpers)));
1481 LcnfExpr::Case {
1482 scrutinee: *scrutinee,
1483 scrutinee_ty: scrutinee_ty.clone(),
1484 alts: new_alts,
1485 default: new_default,
1486 }
1487 }
1488 other => other.clone(),
1489 }
1490 }
1491 pub(super) fn convert_let_value(
1493 &mut self,
1494 value: &LcnfLetValue,
1495 _parent_fn: &str,
1496 _helpers: &mut Vec<LcnfFunDecl>,
1497 ) -> LcnfLetValue {
1498 match value {
1499 LcnfLetValue::App(func, _args) => {
1500 if self.config.defunctionalize {
1501 if let LcnfArg::Var(_fvar) = func {}
1502 }
1503 value.clone()
1504 }
1505 LcnfLetValue::Ctor(_name, _tag, _args) => value.clone(),
1506 _ => value.clone(),
1507 }
1508 }
1509 pub fn defunctionalize(
1514 &mut self,
1515 call_site_var: LcnfVarId,
1516 possible_callees: &[String],
1517 ) -> Option<LcnfExpr> {
1518 if possible_callees.is_empty() || !self.config.defunctionalize {
1519 return None;
1520 }
1521 self.stats.defunctionalized += 1;
1522 let alts: Vec<LcnfAlt> = possible_callees
1523 .iter()
1524 .enumerate()
1525 .map(|(tag, callee_name)| LcnfAlt {
1526 ctor_name: callee_name.clone(),
1527 ctor_tag: tag as u32,
1528 params: vec![],
1529 body: LcnfExpr::Return(LcnfArg::Var(call_site_var)),
1530 })
1531 .collect();
1532 Some(LcnfExpr::Case {
1533 scrutinee: call_site_var,
1534 scrutinee_ty: LcnfType::Object,
1535 alts,
1536 default: Some(Box::new(LcnfExpr::Unreachable)),
1537 })
1538 }
1539 pub fn stack_allocate_closure(&self, info: &ClosureInfo) -> bool {
1541 self.config.stack_alloc_non_escaping
1542 && !info.is_escaping
1543 && info.free_vars.len() <= self.config.max_inline_captures
1544 }
1545 pub fn stats(&self) -> &ClosureConvertStats {
1547 &self.stats
1548 }
1549 pub fn get_closure_info(&self, var: LcnfVarId) -> Option<&ClosureInfo> {
1551 self.closure_infos.get(&var)
1552 }
1553}
1554#[allow(dead_code)]
1556#[derive(Debug, Clone, Default)]
1557pub struct CCExtLiveness {
1558 pub live_in: Vec<Vec<usize>>,
1559 pub live_out: Vec<Vec<usize>>,
1560 pub defs: Vec<Vec<usize>>,
1561 pub uses: Vec<Vec<usize>>,
1562}
1563impl CCExtLiveness {
1564 #[allow(dead_code)]
1565 pub fn new(n: usize) -> Self {
1566 Self {
1567 live_in: vec![Vec::new(); n],
1568 live_out: vec![Vec::new(); n],
1569 defs: vec![Vec::new(); n],
1570 uses: vec![Vec::new(); n],
1571 }
1572 }
1573 #[allow(dead_code)]
1574 pub fn live_in(&self, b: usize, v: usize) -> bool {
1575 self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1576 }
1577 #[allow(dead_code)]
1578 pub fn live_out(&self, b: usize, v: usize) -> bool {
1579 self.live_out
1580 .get(b)
1581 .map(|s| s.contains(&v))
1582 .unwrap_or(false)
1583 }
1584 #[allow(dead_code)]
1585 pub fn add_def(&mut self, b: usize, v: usize) {
1586 if let Some(s) = self.defs.get_mut(b) {
1587 if !s.contains(&v) {
1588 s.push(v);
1589 }
1590 }
1591 }
1592 #[allow(dead_code)]
1593 pub fn add_use(&mut self, b: usize, v: usize) {
1594 if let Some(s) = self.uses.get_mut(b) {
1595 if !s.contains(&v) {
1596 s.push(v);
1597 }
1598 }
1599 }
1600 #[allow(dead_code)]
1601 pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
1602 self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1603 }
1604 #[allow(dead_code)]
1605 pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
1606 self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1607 }
1608}
1609#[derive(Debug, Clone)]
1611pub struct ClosureInfo {
1612 pub free_vars: Vec<LcnfVarId>,
1614 pub captured_types: Vec<LcnfType>,
1616 pub arity: usize,
1618 pub is_escaping: bool,
1620 pub has_side_effects: bool,
1622 pub original_name: Option<String>,
1624}
1625impl ClosureInfo {
1626 pub fn can_stack_allocate(&self) -> bool {
1628 !self.is_escaping
1629 }
1630 pub fn total_fields(&self) -> usize {
1632 1 + self.free_vars.len()
1633 }
1634}
1635#[derive(Debug, Clone)]
1637pub struct ClosureConvertConfig {
1638 pub defunctionalize: bool,
1640 pub stack_alloc_non_escaping: bool,
1642 pub max_inline_captures: usize,
1644 pub merge_closures: bool,
1646}
1647#[allow(dead_code)]
1648#[derive(Debug, Clone, Default)]
1649pub struct CCPassStats {
1650 pub total_runs: u32,
1651 pub successful_runs: u32,
1652 pub total_changes: u64,
1653 pub time_ms: u64,
1654 pub iterations_used: u32,
1655}
1656impl CCPassStats {
1657 #[allow(dead_code)]
1658 pub fn new() -> Self {
1659 Self::default()
1660 }
1661 #[allow(dead_code)]
1662 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
1663 self.total_runs += 1;
1664 self.successful_runs += 1;
1665 self.total_changes += changes;
1666 self.time_ms += time_ms;
1667 self.iterations_used = iterations;
1668 }
1669 #[allow(dead_code)]
1670 pub fn average_changes_per_run(&self) -> f64 {
1671 if self.total_runs == 0 {
1672 return 0.0;
1673 }
1674 self.total_changes as f64 / self.total_runs as f64
1675 }
1676 #[allow(dead_code)]
1677 pub fn success_rate(&self) -> f64 {
1678 if self.total_runs == 0 {
1679 return 0.0;
1680 }
1681 self.successful_runs as f64 / self.total_runs as f64
1682 }
1683 #[allow(dead_code)]
1684 pub fn format_summary(&self) -> String {
1685 format!(
1686 "Runs: {}/{}, Changes: {}, Time: {}ms",
1687 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
1688 )
1689 }
1690}
1691#[allow(dead_code)]
1693#[derive(Debug, Clone)]
1694pub struct CCX2PassConfig {
1695 pub name: String,
1696 pub phase: CCX2PassPhase,
1697 pub enabled: bool,
1698 pub max_iterations: usize,
1699 pub debug: u32,
1700 pub timeout_ms: Option<u64>,
1701}
1702impl CCX2PassConfig {
1703 #[allow(dead_code)]
1704 pub fn new(name: impl Into<String>) -> Self {
1705 Self {
1706 name: name.into(),
1707 phase: CCX2PassPhase::Middle,
1708 enabled: true,
1709 max_iterations: 100,
1710 debug: 0,
1711 timeout_ms: None,
1712 }
1713 }
1714 #[allow(dead_code)]
1715 pub fn with_phase(mut self, phase: CCX2PassPhase) -> Self {
1716 self.phase = phase;
1717 self
1718 }
1719 #[allow(dead_code)]
1720 pub fn with_max_iter(mut self, n: usize) -> Self {
1721 self.max_iterations = n;
1722 self
1723 }
1724 #[allow(dead_code)]
1725 pub fn with_debug(mut self, d: u32) -> Self {
1726 self.debug = d;
1727 self
1728 }
1729 #[allow(dead_code)]
1730 pub fn disabled(mut self) -> Self {
1731 self.enabled = false;
1732 self
1733 }
1734 #[allow(dead_code)]
1735 pub fn with_timeout(mut self, ms: u64) -> Self {
1736 self.timeout_ms = Some(ms);
1737 self
1738 }
1739 #[allow(dead_code)]
1740 pub fn is_debug_enabled(&self) -> bool {
1741 self.debug > 0
1742 }
1743}
1744#[allow(dead_code)]
1745#[derive(Debug, Clone)]
1746pub struct CCLivenessInfo {
1747 pub live_in: Vec<std::collections::HashSet<u32>>,
1748 pub live_out: Vec<std::collections::HashSet<u32>>,
1749 pub defs: Vec<std::collections::HashSet<u32>>,
1750 pub uses: Vec<std::collections::HashSet<u32>>,
1751}
1752impl CCLivenessInfo {
1753 #[allow(dead_code)]
1754 pub fn new(block_count: usize) -> Self {
1755 CCLivenessInfo {
1756 live_in: vec![std::collections::HashSet::new(); block_count],
1757 live_out: vec![std::collections::HashSet::new(); block_count],
1758 defs: vec![std::collections::HashSet::new(); block_count],
1759 uses: vec![std::collections::HashSet::new(); block_count],
1760 }
1761 }
1762 #[allow(dead_code)]
1763 pub fn add_def(&mut self, block: usize, var: u32) {
1764 if block < self.defs.len() {
1765 self.defs[block].insert(var);
1766 }
1767 }
1768 #[allow(dead_code)]
1769 pub fn add_use(&mut self, block: usize, var: u32) {
1770 if block < self.uses.len() {
1771 self.uses[block].insert(var);
1772 }
1773 }
1774 #[allow(dead_code)]
1775 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1776 self.live_in
1777 .get(block)
1778 .map(|s| s.contains(&var))
1779 .unwrap_or(false)
1780 }
1781 #[allow(dead_code)]
1782 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1783 self.live_out
1784 .get(block)
1785 .map(|s| s.contains(&var))
1786 .unwrap_or(false)
1787 }
1788}
1789#[allow(dead_code)]
1791#[derive(Debug, Clone)]
1792pub struct CCExtWorklist {
1793 pub(super) items: std::collections::VecDeque<usize>,
1794 pub(super) present: Vec<bool>,
1795}
1796impl CCExtWorklist {
1797 #[allow(dead_code)]
1798 pub fn new(capacity: usize) -> Self {
1799 Self {
1800 items: std::collections::VecDeque::new(),
1801 present: vec![false; capacity],
1802 }
1803 }
1804 #[allow(dead_code)]
1805 pub fn push(&mut self, id: usize) {
1806 if id < self.present.len() && !self.present[id] {
1807 self.present[id] = true;
1808 self.items.push_back(id);
1809 }
1810 }
1811 #[allow(dead_code)]
1812 pub fn push_front(&mut self, id: usize) {
1813 if id < self.present.len() && !self.present[id] {
1814 self.present[id] = true;
1815 self.items.push_front(id);
1816 }
1817 }
1818 #[allow(dead_code)]
1819 pub fn pop(&mut self) -> Option<usize> {
1820 let id = self.items.pop_front()?;
1821 if id < self.present.len() {
1822 self.present[id] = false;
1823 }
1824 Some(id)
1825 }
1826 #[allow(dead_code)]
1827 pub fn is_empty(&self) -> bool {
1828 self.items.is_empty()
1829 }
1830 #[allow(dead_code)]
1831 pub fn len(&self) -> usize {
1832 self.items.len()
1833 }
1834 #[allow(dead_code)]
1835 pub fn contains(&self, id: usize) -> bool {
1836 id < self.present.len() && self.present[id]
1837 }
1838 #[allow(dead_code)]
1839 pub fn drain_all(&mut self) -> Vec<usize> {
1840 let v: Vec<usize> = self.items.drain(..).collect();
1841 for &id in &v {
1842 if id < self.present.len() {
1843 self.present[id] = false;
1844 }
1845 }
1846 v
1847 }
1848}
1849#[allow(dead_code)]
1851#[derive(Debug, Clone)]
1852pub struct CCX2Worklist {
1853 pub(super) items: std::collections::VecDeque<usize>,
1854 pub(super) present: Vec<bool>,
1855}
1856impl CCX2Worklist {
1857 #[allow(dead_code)]
1858 pub fn new(capacity: usize) -> Self {
1859 Self {
1860 items: std::collections::VecDeque::new(),
1861 present: vec![false; capacity],
1862 }
1863 }
1864 #[allow(dead_code)]
1865 pub fn push(&mut self, id: usize) {
1866 if id < self.present.len() && !self.present[id] {
1867 self.present[id] = true;
1868 self.items.push_back(id);
1869 }
1870 }
1871 #[allow(dead_code)]
1872 pub fn push_front(&mut self, id: usize) {
1873 if id < self.present.len() && !self.present[id] {
1874 self.present[id] = true;
1875 self.items.push_front(id);
1876 }
1877 }
1878 #[allow(dead_code)]
1879 pub fn pop(&mut self) -> Option<usize> {
1880 let id = self.items.pop_front()?;
1881 if id < self.present.len() {
1882 self.present[id] = false;
1883 }
1884 Some(id)
1885 }
1886 #[allow(dead_code)]
1887 pub fn is_empty(&self) -> bool {
1888 self.items.is_empty()
1889 }
1890 #[allow(dead_code)]
1891 pub fn len(&self) -> usize {
1892 self.items.len()
1893 }
1894 #[allow(dead_code)]
1895 pub fn contains(&self, id: usize) -> bool {
1896 id < self.present.len() && self.present[id]
1897 }
1898 #[allow(dead_code)]
1899 pub fn drain_all(&mut self) -> Vec<usize> {
1900 let v: Vec<usize> = self.items.drain(..).collect();
1901 for &id in &v {
1902 if id < self.present.len() {
1903 self.present[id] = false;
1904 }
1905 }
1906 v
1907 }
1908}
1909#[allow(dead_code)]
1911#[derive(Debug, Clone)]
1912pub struct CCX2DomTree {
1913 pub(super) idom: Vec<Option<usize>>,
1914 pub(super) children: Vec<Vec<usize>>,
1915 pub(super) depth: Vec<usize>,
1916}
1917impl CCX2DomTree {
1918 #[allow(dead_code)]
1919 pub fn new(n: usize) -> Self {
1920 Self {
1921 idom: vec![None; n],
1922 children: vec![Vec::new(); n],
1923 depth: vec![0; n],
1924 }
1925 }
1926 #[allow(dead_code)]
1927 pub fn set_idom(&mut self, node: usize, dom: usize) {
1928 if node < self.idom.len() {
1929 self.idom[node] = Some(dom);
1930 if dom < self.children.len() {
1931 self.children[dom].push(node);
1932 }
1933 self.depth[node] = if dom < self.depth.len() {
1934 self.depth[dom] + 1
1935 } else {
1936 1
1937 };
1938 }
1939 }
1940 #[allow(dead_code)]
1941 pub fn dominates(&self, a: usize, mut b: usize) -> bool {
1942 if a == b {
1943 return true;
1944 }
1945 let n = self.idom.len();
1946 for _ in 0..n {
1947 match self.idom.get(b).copied().flatten() {
1948 None => return false,
1949 Some(p) if p == a => return true,
1950 Some(p) if p == b => return false,
1951 Some(p) => b = p,
1952 }
1953 }
1954 false
1955 }
1956 #[allow(dead_code)]
1957 pub fn children_of(&self, n: usize) -> &[usize] {
1958 self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1959 }
1960 #[allow(dead_code)]
1961 pub fn depth_of(&self, n: usize) -> usize {
1962 self.depth.get(n).copied().unwrap_or(0)
1963 }
1964 #[allow(dead_code)]
1965 pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
1966 let n = self.idom.len();
1967 for _ in 0..(2 * n) {
1968 if a == b {
1969 return a;
1970 }
1971 if self.depth_of(a) > self.depth_of(b) {
1972 a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
1973 } else {
1974 b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
1975 }
1976 }
1977 0
1978 }
1979}
1980#[allow(dead_code)]
1982#[derive(Debug)]
1983pub struct CCX2Cache {
1984 pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
1985 pub(super) cap: usize,
1986 pub(super) total_hits: u64,
1987 pub(super) total_misses: u64,
1988}
1989impl CCX2Cache {
1990 #[allow(dead_code)]
1991 pub fn new(cap: usize) -> Self {
1992 Self {
1993 entries: Vec::new(),
1994 cap,
1995 total_hits: 0,
1996 total_misses: 0,
1997 }
1998 }
1999 #[allow(dead_code)]
2000 pub fn get(&mut self, key: u64) -> Option<&[u8]> {
2001 for e in self.entries.iter_mut() {
2002 if e.0 == key && e.2 {
2003 e.3 += 1;
2004 self.total_hits += 1;
2005 return Some(&e.1);
2006 }
2007 }
2008 self.total_misses += 1;
2009 None
2010 }
2011 #[allow(dead_code)]
2012 pub fn put(&mut self, key: u64, data: Vec<u8>) {
2013 if self.entries.len() >= self.cap {
2014 self.entries.retain(|e| e.2);
2015 if self.entries.len() >= self.cap {
2016 self.entries.remove(0);
2017 }
2018 }
2019 self.entries.push((key, data, true, 0));
2020 }
2021 #[allow(dead_code)]
2022 pub fn invalidate(&mut self) {
2023 for e in self.entries.iter_mut() {
2024 e.2 = false;
2025 }
2026 }
2027 #[allow(dead_code)]
2028 pub fn hit_rate(&self) -> f64 {
2029 let t = self.total_hits + self.total_misses;
2030 if t == 0 {
2031 0.0
2032 } else {
2033 self.total_hits as f64 / t as f64
2034 }
2035 }
2036 #[allow(dead_code)]
2037 pub fn live_count(&self) -> usize {
2038 self.entries.iter().filter(|e| e.2).count()
2039 }
2040}
2041#[allow(dead_code)]
2042#[derive(Debug, Clone)]
2043pub struct CCWorklist {
2044 pub(super) items: std::collections::VecDeque<u32>,
2045 pub(super) in_worklist: std::collections::HashSet<u32>,
2046}
2047impl CCWorklist {
2048 #[allow(dead_code)]
2049 pub fn new() -> Self {
2050 CCWorklist {
2051 items: std::collections::VecDeque::new(),
2052 in_worklist: std::collections::HashSet::new(),
2053 }
2054 }
2055 #[allow(dead_code)]
2056 pub fn push(&mut self, item: u32) -> bool {
2057 if self.in_worklist.insert(item) {
2058 self.items.push_back(item);
2059 true
2060 } else {
2061 false
2062 }
2063 }
2064 #[allow(dead_code)]
2065 pub fn pop(&mut self) -> Option<u32> {
2066 let item = self.items.pop_front()?;
2067 self.in_worklist.remove(&item);
2068 Some(item)
2069 }
2070 #[allow(dead_code)]
2071 pub fn is_empty(&self) -> bool {
2072 self.items.is_empty()
2073 }
2074 #[allow(dead_code)]
2075 pub fn len(&self) -> usize {
2076 self.items.len()
2077 }
2078 #[allow(dead_code)]
2079 pub fn contains(&self, item: u32) -> bool {
2080 self.in_worklist.contains(&item)
2081 }
2082}
2083#[allow(dead_code)]
2085#[derive(Debug, Clone, Default)]
2086pub struct CCX2Liveness {
2087 pub live_in: Vec<Vec<usize>>,
2088 pub live_out: Vec<Vec<usize>>,
2089 pub defs: Vec<Vec<usize>>,
2090 pub uses: Vec<Vec<usize>>,
2091}
2092impl CCX2Liveness {
2093 #[allow(dead_code)]
2094 pub fn new(n: usize) -> Self {
2095 Self {
2096 live_in: vec![Vec::new(); n],
2097 live_out: vec![Vec::new(); n],
2098 defs: vec![Vec::new(); n],
2099 uses: vec![Vec::new(); n],
2100 }
2101 }
2102 #[allow(dead_code)]
2103 pub fn live_in(&self, b: usize, v: usize) -> bool {
2104 self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2105 }
2106 #[allow(dead_code)]
2107 pub fn live_out(&self, b: usize, v: usize) -> bool {
2108 self.live_out
2109 .get(b)
2110 .map(|s| s.contains(&v))
2111 .unwrap_or(false)
2112 }
2113 #[allow(dead_code)]
2114 pub fn add_def(&mut self, b: usize, v: usize) {
2115 if let Some(s) = self.defs.get_mut(b) {
2116 if !s.contains(&v) {
2117 s.push(v);
2118 }
2119 }
2120 }
2121 #[allow(dead_code)]
2122 pub fn add_use(&mut self, b: usize, v: usize) {
2123 if let Some(s) = self.uses.get_mut(b) {
2124 if !s.contains(&v) {
2125 s.push(v);
2126 }
2127 }
2128 }
2129 #[allow(dead_code)]
2130 pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
2131 self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2132 }
2133 #[allow(dead_code)]
2134 pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
2135 self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2136 }
2137}
2138#[allow(dead_code)]
2140#[derive(Debug, Default)]
2141pub struct CCExtPassRegistry {
2142 pub(super) configs: Vec<CCExtPassConfig>,
2143 pub(super) stats: Vec<CCExtPassStats>,
2144}
2145impl CCExtPassRegistry {
2146 #[allow(dead_code)]
2147 pub fn new() -> Self {
2148 Self::default()
2149 }
2150 #[allow(dead_code)]
2151 pub fn register(&mut self, c: CCExtPassConfig) {
2152 self.stats.push(CCExtPassStats::new());
2153 self.configs.push(c);
2154 }
2155 #[allow(dead_code)]
2156 pub fn len(&self) -> usize {
2157 self.configs.len()
2158 }
2159 #[allow(dead_code)]
2160 pub fn is_empty(&self) -> bool {
2161 self.configs.is_empty()
2162 }
2163 #[allow(dead_code)]
2164 pub fn get(&self, i: usize) -> Option<&CCExtPassConfig> {
2165 self.configs.get(i)
2166 }
2167 #[allow(dead_code)]
2168 pub fn get_stats(&self, i: usize) -> Option<&CCExtPassStats> {
2169 self.stats.get(i)
2170 }
2171 #[allow(dead_code)]
2172 pub fn enabled_passes(&self) -> Vec<&CCExtPassConfig> {
2173 self.configs.iter().filter(|c| c.enabled).collect()
2174 }
2175 #[allow(dead_code)]
2176 pub fn passes_in_phase(&self, ph: &CCExtPassPhase) -> Vec<&CCExtPassConfig> {
2177 self.configs
2178 .iter()
2179 .filter(|c| c.enabled && &c.phase == ph)
2180 .collect()
2181 }
2182 #[allow(dead_code)]
2183 pub fn total_nodes_visited(&self) -> usize {
2184 self.stats.iter().map(|s| s.nodes_visited).sum()
2185 }
2186 #[allow(dead_code)]
2187 pub fn any_changed(&self) -> bool {
2188 self.stats.iter().any(|s| s.changed)
2189 }
2190}
2191#[allow(dead_code)]
2193#[derive(Debug, Clone, Default)]
2194pub struct CCX2PassStats {
2195 pub iterations: usize,
2196 pub changed: bool,
2197 pub nodes_visited: usize,
2198 pub nodes_modified: usize,
2199 pub time_ms: u64,
2200 pub memory_bytes: usize,
2201 pub errors: usize,
2202}
2203impl CCX2PassStats {
2204 #[allow(dead_code)]
2205 pub fn new() -> Self {
2206 Self::default()
2207 }
2208 #[allow(dead_code)]
2209 pub fn visit(&mut self) {
2210 self.nodes_visited += 1;
2211 }
2212 #[allow(dead_code)]
2213 pub fn modify(&mut self) {
2214 self.nodes_modified += 1;
2215 self.changed = true;
2216 }
2217 #[allow(dead_code)]
2218 pub fn iterate(&mut self) {
2219 self.iterations += 1;
2220 }
2221 #[allow(dead_code)]
2222 pub fn error(&mut self) {
2223 self.errors += 1;
2224 }
2225 #[allow(dead_code)]
2226 pub fn efficiency(&self) -> f64 {
2227 if self.nodes_visited == 0 {
2228 0.0
2229 } else {
2230 self.nodes_modified as f64 / self.nodes_visited as f64
2231 }
2232 }
2233 #[allow(dead_code)]
2234 pub fn merge(&mut self, o: &CCX2PassStats) {
2235 self.iterations += o.iterations;
2236 self.changed |= o.changed;
2237 self.nodes_visited += o.nodes_visited;
2238 self.nodes_modified += o.nodes_modified;
2239 self.time_ms += o.time_ms;
2240 self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
2241 self.errors += o.errors;
2242 }
2243}
2244#[allow(dead_code)]
2246#[derive(Debug, Clone)]
2247pub struct CCX2DepGraph {
2248 pub(super) n: usize,
2249 pub(super) adj: Vec<Vec<usize>>,
2250 pub(super) rev: Vec<Vec<usize>>,
2251 pub(super) edge_count: usize,
2252}
2253impl CCX2DepGraph {
2254 #[allow(dead_code)]
2255 pub fn new(n: usize) -> Self {
2256 Self {
2257 n,
2258 adj: vec![Vec::new(); n],
2259 rev: vec![Vec::new(); n],
2260 edge_count: 0,
2261 }
2262 }
2263 #[allow(dead_code)]
2264 pub fn add_edge(&mut self, from: usize, to: usize) {
2265 if from < self.n && to < self.n {
2266 if !self.adj[from].contains(&to) {
2267 self.adj[from].push(to);
2268 self.rev[to].push(from);
2269 self.edge_count += 1;
2270 }
2271 }
2272 }
2273 #[allow(dead_code)]
2274 pub fn succs(&self, n: usize) -> &[usize] {
2275 self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
2276 }
2277 #[allow(dead_code)]
2278 pub fn preds(&self, n: usize) -> &[usize] {
2279 self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
2280 }
2281 #[allow(dead_code)]
2282 pub fn topo_sort(&self) -> Option<Vec<usize>> {
2283 let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
2284 let mut q: std::collections::VecDeque<usize> =
2285 (0..self.n).filter(|&i| deg[i] == 0).collect();
2286 let mut out = Vec::with_capacity(self.n);
2287 while let Some(u) = q.pop_front() {
2288 out.push(u);
2289 for &v in &self.adj[u] {
2290 deg[v] -= 1;
2291 if deg[v] == 0 {
2292 q.push_back(v);
2293 }
2294 }
2295 }
2296 if out.len() == self.n {
2297 Some(out)
2298 } else {
2299 None
2300 }
2301 }
2302 #[allow(dead_code)]
2303 pub fn has_cycle(&self) -> bool {
2304 self.topo_sort().is_none()
2305 }
2306 #[allow(dead_code)]
2307 pub fn reachable(&self, start: usize) -> Vec<usize> {
2308 let mut vis = vec![false; self.n];
2309 let mut stk = vec![start];
2310 let mut out = Vec::new();
2311 while let Some(u) = stk.pop() {
2312 if u < self.n && !vis[u] {
2313 vis[u] = true;
2314 out.push(u);
2315 for &v in &self.adj[u] {
2316 if !vis[v] {
2317 stk.push(v);
2318 }
2319 }
2320 }
2321 }
2322 out
2323 }
2324 #[allow(dead_code)]
2325 pub fn scc(&self) -> Vec<Vec<usize>> {
2326 let mut visited = vec![false; self.n];
2327 let mut order = Vec::new();
2328 for i in 0..self.n {
2329 if !visited[i] {
2330 let mut stk = vec![(i, 0usize)];
2331 while let Some((u, idx)) = stk.last_mut() {
2332 if !visited[*u] {
2333 visited[*u] = true;
2334 }
2335 if *idx < self.adj[*u].len() {
2336 let v = self.adj[*u][*idx];
2337 *idx += 1;
2338 if !visited[v] {
2339 stk.push((v, 0));
2340 }
2341 } else {
2342 order.push(*u);
2343 stk.pop();
2344 }
2345 }
2346 }
2347 }
2348 let mut comp = vec![usize::MAX; self.n];
2349 let mut components: Vec<Vec<usize>> = Vec::new();
2350 for &start in order.iter().rev() {
2351 if comp[start] == usize::MAX {
2352 let cid = components.len();
2353 let mut component = Vec::new();
2354 let mut stk = vec![start];
2355 while let Some(u) = stk.pop() {
2356 if comp[u] == usize::MAX {
2357 comp[u] = cid;
2358 component.push(u);
2359 for &v in &self.rev[u] {
2360 if comp[v] == usize::MAX {
2361 stk.push(v);
2362 }
2363 }
2364 }
2365 }
2366 components.push(component);
2367 }
2368 }
2369 components
2370 }
2371 #[allow(dead_code)]
2372 pub fn node_count(&self) -> usize {
2373 self.n
2374 }
2375 #[allow(dead_code)]
2376 pub fn edge_count(&self) -> usize {
2377 self.edge_count
2378 }
2379}