1use super::functions::*;
6use std::collections::{HashMap, HashSet, VecDeque};
7
8#[allow(dead_code)]
10#[derive(Debug, Default)]
11pub struct VerilogExtPassRegistry {
12 pub(super) configs: Vec<VerilogExtPassConfig>,
13 pub(super) stats: Vec<VerilogExtPassStats>,
14}
15impl VerilogExtPassRegistry {
16 #[allow(dead_code)]
17 pub fn new() -> Self {
18 Self::default()
19 }
20 #[allow(dead_code)]
21 pub fn register(&mut self, c: VerilogExtPassConfig) {
22 self.stats.push(VerilogExtPassStats::new());
23 self.configs.push(c);
24 }
25 #[allow(dead_code)]
26 pub fn len(&self) -> usize {
27 self.configs.len()
28 }
29 #[allow(dead_code)]
30 pub fn is_empty(&self) -> bool {
31 self.configs.is_empty()
32 }
33 #[allow(dead_code)]
34 pub fn get(&self, i: usize) -> Option<&VerilogExtPassConfig> {
35 self.configs.get(i)
36 }
37 #[allow(dead_code)]
38 pub fn get_stats(&self, i: usize) -> Option<&VerilogExtPassStats> {
39 self.stats.get(i)
40 }
41 #[allow(dead_code)]
42 pub fn enabled_passes(&self) -> Vec<&VerilogExtPassConfig> {
43 self.configs.iter().filter(|c| c.enabled).collect()
44 }
45 #[allow(dead_code)]
46 pub fn passes_in_phase(&self, ph: &VerilogExtPassPhase) -> Vec<&VerilogExtPassConfig> {
47 self.configs
48 .iter()
49 .filter(|c| c.enabled && &c.phase == ph)
50 .collect()
51 }
52 #[allow(dead_code)]
53 pub fn total_nodes_visited(&self) -> usize {
54 self.stats.iter().map(|s| s.nodes_visited).sum()
55 }
56 #[allow(dead_code)]
57 pub fn any_changed(&self) -> bool {
58 self.stats.iter().any(|s| s.changed)
59 }
60}
61#[allow(dead_code)]
62#[derive(Debug, Clone)]
63pub struct VlogPassConfig {
64 pub phase: VlogPassPhase,
65 pub enabled: bool,
66 pub max_iterations: u32,
67 pub debug_output: bool,
68 pub pass_name: String,
69}
70impl VlogPassConfig {
71 #[allow(dead_code)]
72 pub fn new(name: impl Into<String>, phase: VlogPassPhase) -> Self {
73 VlogPassConfig {
74 phase,
75 enabled: true,
76 max_iterations: 10,
77 debug_output: false,
78 pass_name: name.into(),
79 }
80 }
81 #[allow(dead_code)]
82 pub fn disabled(mut self) -> Self {
83 self.enabled = false;
84 self
85 }
86 #[allow(dead_code)]
87 pub fn with_debug(mut self) -> Self {
88 self.debug_output = true;
89 self
90 }
91 #[allow(dead_code)]
92 pub fn max_iter(mut self, n: u32) -> Self {
93 self.max_iterations = n;
94 self
95 }
96}
97#[allow(dead_code)]
99#[derive(Debug, Clone)]
100pub struct VerilogX2DomTree {
101 pub(super) idom: Vec<Option<usize>>,
102 pub(super) children: Vec<Vec<usize>>,
103 pub(super) depth: Vec<usize>,
104}
105impl VerilogX2DomTree {
106 #[allow(dead_code)]
107 pub fn new(n: usize) -> Self {
108 Self {
109 idom: vec![None; n],
110 children: vec![Vec::new(); n],
111 depth: vec![0; n],
112 }
113 }
114 #[allow(dead_code)]
115 pub fn set_idom(&mut self, node: usize, dom: usize) {
116 if node < self.idom.len() {
117 self.idom[node] = Some(dom);
118 if dom < self.children.len() {
119 self.children[dom].push(node);
120 }
121 self.depth[node] = if dom < self.depth.len() {
122 self.depth[dom] + 1
123 } else {
124 1
125 };
126 }
127 }
128 #[allow(dead_code)]
129 pub fn dominates(&self, a: usize, mut b: usize) -> bool {
130 if a == b {
131 return true;
132 }
133 let n = self.idom.len();
134 for _ in 0..n {
135 match self.idom.get(b).copied().flatten() {
136 None => return false,
137 Some(p) if p == a => return true,
138 Some(p) if p == b => return false,
139 Some(p) => b = p,
140 }
141 }
142 false
143 }
144 #[allow(dead_code)]
145 pub fn children_of(&self, n: usize) -> &[usize] {
146 self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
147 }
148 #[allow(dead_code)]
149 pub fn depth_of(&self, n: usize) -> usize {
150 self.depth.get(n).copied().unwrap_or(0)
151 }
152 #[allow(dead_code)]
153 pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
154 let n = self.idom.len();
155 for _ in 0..(2 * n) {
156 if a == b {
157 return a;
158 }
159 if self.depth_of(a) > self.depth_of(b) {
160 a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
161 } else {
162 b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
163 }
164 }
165 0
166 }
167}
168#[allow(dead_code)]
170#[derive(Debug, Clone, Default)]
171pub struct VerilogX2PassStats {
172 pub iterations: usize,
173 pub changed: bool,
174 pub nodes_visited: usize,
175 pub nodes_modified: usize,
176 pub time_ms: u64,
177 pub memory_bytes: usize,
178 pub errors: usize,
179}
180impl VerilogX2PassStats {
181 #[allow(dead_code)]
182 pub fn new() -> Self {
183 Self::default()
184 }
185 #[allow(dead_code)]
186 pub fn visit(&mut self) {
187 self.nodes_visited += 1;
188 }
189 #[allow(dead_code)]
190 pub fn modify(&mut self) {
191 self.nodes_modified += 1;
192 self.changed = true;
193 }
194 #[allow(dead_code)]
195 pub fn iterate(&mut self) {
196 self.iterations += 1;
197 }
198 #[allow(dead_code)]
199 pub fn error(&mut self) {
200 self.errors += 1;
201 }
202 #[allow(dead_code)]
203 pub fn efficiency(&self) -> f64 {
204 if self.nodes_visited == 0 {
205 0.0
206 } else {
207 self.nodes_modified as f64 / self.nodes_visited as f64
208 }
209 }
210 #[allow(dead_code)]
211 pub fn merge(&mut self, o: &VerilogX2PassStats) {
212 self.iterations += o.iterations;
213 self.changed |= o.changed;
214 self.nodes_visited += o.nodes_visited;
215 self.nodes_modified += o.nodes_modified;
216 self.time_ms += o.time_ms;
217 self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
218 self.errors += o.errors;
219 }
220}
221#[allow(dead_code)]
222#[derive(Debug, Clone)]
223pub struct VlogLivenessInfo {
224 pub live_in: Vec<std::collections::HashSet<u32>>,
225 pub live_out: Vec<std::collections::HashSet<u32>>,
226 pub defs: Vec<std::collections::HashSet<u32>>,
227 pub uses: Vec<std::collections::HashSet<u32>>,
228}
229impl VlogLivenessInfo {
230 #[allow(dead_code)]
231 pub fn new(block_count: usize) -> Self {
232 VlogLivenessInfo {
233 live_in: vec![std::collections::HashSet::new(); block_count],
234 live_out: vec![std::collections::HashSet::new(); block_count],
235 defs: vec![std::collections::HashSet::new(); block_count],
236 uses: vec![std::collections::HashSet::new(); block_count],
237 }
238 }
239 #[allow(dead_code)]
240 pub fn add_def(&mut self, block: usize, var: u32) {
241 if block < self.defs.len() {
242 self.defs[block].insert(var);
243 }
244 }
245 #[allow(dead_code)]
246 pub fn add_use(&mut self, block: usize, var: u32) {
247 if block < self.uses.len() {
248 self.uses[block].insert(var);
249 }
250 }
251 #[allow(dead_code)]
252 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
253 self.live_in
254 .get(block)
255 .map(|s| s.contains(&var))
256 .unwrap_or(false)
257 }
258 #[allow(dead_code)]
259 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
260 self.live_out
261 .get(block)
262 .map(|s| s.contains(&var))
263 .unwrap_or(false)
264 }
265}
266#[allow(dead_code)]
268#[derive(Debug, Clone, Default)]
269pub struct VerilogExtPassStats {
270 pub iterations: usize,
271 pub changed: bool,
272 pub nodes_visited: usize,
273 pub nodes_modified: usize,
274 pub time_ms: u64,
275 pub memory_bytes: usize,
276 pub errors: usize,
277}
278impl VerilogExtPassStats {
279 #[allow(dead_code)]
280 pub fn new() -> Self {
281 Self::default()
282 }
283 #[allow(dead_code)]
284 pub fn visit(&mut self) {
285 self.nodes_visited += 1;
286 }
287 #[allow(dead_code)]
288 pub fn modify(&mut self) {
289 self.nodes_modified += 1;
290 self.changed = true;
291 }
292 #[allow(dead_code)]
293 pub fn iterate(&mut self) {
294 self.iterations += 1;
295 }
296 #[allow(dead_code)]
297 pub fn error(&mut self) {
298 self.errors += 1;
299 }
300 #[allow(dead_code)]
301 pub fn efficiency(&self) -> f64 {
302 if self.nodes_visited == 0 {
303 0.0
304 } else {
305 self.nodes_modified as f64 / self.nodes_visited as f64
306 }
307 }
308 #[allow(dead_code)]
309 pub fn merge(&mut self, o: &VerilogExtPassStats) {
310 self.iterations += o.iterations;
311 self.changed |= o.changed;
312 self.nodes_visited += o.nodes_visited;
313 self.nodes_modified += o.nodes_modified;
314 self.time_ms += o.time_ms;
315 self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
316 self.errors += o.errors;
317 }
318}
319#[allow(dead_code)]
321#[derive(Debug, Clone)]
322pub struct VerilogExtDepGraph {
323 pub(super) n: usize,
324 pub(super) adj: Vec<Vec<usize>>,
325 pub(super) rev: Vec<Vec<usize>>,
326 pub(super) edge_count: usize,
327}
328impl VerilogExtDepGraph {
329 #[allow(dead_code)]
330 pub fn new(n: usize) -> Self {
331 Self {
332 n,
333 adj: vec![Vec::new(); n],
334 rev: vec![Vec::new(); n],
335 edge_count: 0,
336 }
337 }
338 #[allow(dead_code)]
339 pub fn add_edge(&mut self, from: usize, to: usize) {
340 if from < self.n && to < self.n {
341 if !self.adj[from].contains(&to) {
342 self.adj[from].push(to);
343 self.rev[to].push(from);
344 self.edge_count += 1;
345 }
346 }
347 }
348 #[allow(dead_code)]
349 pub fn succs(&self, n: usize) -> &[usize] {
350 self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
351 }
352 #[allow(dead_code)]
353 pub fn preds(&self, n: usize) -> &[usize] {
354 self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
355 }
356 #[allow(dead_code)]
357 pub fn topo_sort(&self) -> Option<Vec<usize>> {
358 let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
359 let mut q: std::collections::VecDeque<usize> =
360 (0..self.n).filter(|&i| deg[i] == 0).collect();
361 let mut out = Vec::with_capacity(self.n);
362 while let Some(u) = q.pop_front() {
363 out.push(u);
364 for &v in &self.adj[u] {
365 deg[v] -= 1;
366 if deg[v] == 0 {
367 q.push_back(v);
368 }
369 }
370 }
371 if out.len() == self.n {
372 Some(out)
373 } else {
374 None
375 }
376 }
377 #[allow(dead_code)]
378 pub fn has_cycle(&self) -> bool {
379 self.topo_sort().is_none()
380 }
381 #[allow(dead_code)]
382 pub fn reachable(&self, start: usize) -> Vec<usize> {
383 let mut vis = vec![false; self.n];
384 let mut stk = vec![start];
385 let mut out = Vec::new();
386 while let Some(u) = stk.pop() {
387 if u < self.n && !vis[u] {
388 vis[u] = true;
389 out.push(u);
390 for &v in &self.adj[u] {
391 if !vis[v] {
392 stk.push(v);
393 }
394 }
395 }
396 }
397 out
398 }
399 #[allow(dead_code)]
400 pub fn scc(&self) -> Vec<Vec<usize>> {
401 let mut visited = vec![false; self.n];
402 let mut order = Vec::new();
403 for i in 0..self.n {
404 if !visited[i] {
405 let mut stk = vec![(i, 0usize)];
406 while let Some((u, idx)) = stk.last_mut() {
407 if !visited[*u] {
408 visited[*u] = true;
409 }
410 if *idx < self.adj[*u].len() {
411 let v = self.adj[*u][*idx];
412 *idx += 1;
413 if !visited[v] {
414 stk.push((v, 0));
415 }
416 } else {
417 order.push(*u);
418 stk.pop();
419 }
420 }
421 }
422 }
423 let mut comp = vec![usize::MAX; self.n];
424 let mut components: Vec<Vec<usize>> = Vec::new();
425 for &start in order.iter().rev() {
426 if comp[start] == usize::MAX {
427 let cid = components.len();
428 let mut component = Vec::new();
429 let mut stk = vec![start];
430 while let Some(u) = stk.pop() {
431 if comp[u] == usize::MAX {
432 comp[u] = cid;
433 component.push(u);
434 for &v in &self.rev[u] {
435 if comp[v] == usize::MAX {
436 stk.push(v);
437 }
438 }
439 }
440 }
441 components.push(component);
442 }
443 }
444 components
445 }
446 #[allow(dead_code)]
447 pub fn node_count(&self) -> usize {
448 self.n
449 }
450 #[allow(dead_code)]
451 pub fn edge_count(&self) -> usize {
452 self.edge_count
453 }
454}
455#[allow(dead_code)]
457#[derive(Debug, Clone, PartialEq, Eq, Hash)]
458pub enum VerilogX2PassPhase {
459 Early,
460 Middle,
461 Late,
462 Finalize,
463}
464impl VerilogX2PassPhase {
465 #[allow(dead_code)]
466 pub fn is_early(&self) -> bool {
467 matches!(self, Self::Early)
468 }
469 #[allow(dead_code)]
470 pub fn is_middle(&self) -> bool {
471 matches!(self, Self::Middle)
472 }
473 #[allow(dead_code)]
474 pub fn is_late(&self) -> bool {
475 matches!(self, Self::Late)
476 }
477 #[allow(dead_code)]
478 pub fn is_finalize(&self) -> bool {
479 matches!(self, Self::Finalize)
480 }
481 #[allow(dead_code)]
482 pub fn order(&self) -> u32 {
483 match self {
484 Self::Early => 0,
485 Self::Middle => 1,
486 Self::Late => 2,
487 Self::Finalize => 3,
488 }
489 }
490 #[allow(dead_code)]
491 pub fn from_order(n: u32) -> Option<Self> {
492 match n {
493 0 => Some(Self::Early),
494 1 => Some(Self::Middle),
495 2 => Some(Self::Late),
496 3 => Some(Self::Finalize),
497 _ => None,
498 }
499 }
500}
501#[derive(Debug, Clone)]
503pub struct VerilogModule {
504 pub name: String,
506 pub ports: Vec<VerilogPort>,
508 pub params: Vec<(String, u64)>,
510 pub body: Vec<String>,
512}
513impl VerilogModule {
514 pub fn new(name: impl Into<String>) -> Self {
516 VerilogModule {
517 name: name.into(),
518 ports: Vec::new(),
519 params: Vec::new(),
520 body: Vec::new(),
521 }
522 }
523 pub fn add_port(&mut self, port: VerilogPort) {
525 self.ports.push(port);
526 }
527 pub fn add_param(&mut self, name: impl Into<String>, default: u64) {
529 self.params.push((name.into(), default));
530 }
531 pub fn add_stmt(&mut self, stmt: impl Into<String>) {
533 self.body.push(stmt.into());
534 }
535}
536#[allow(dead_code)]
537#[derive(Debug, Clone, Default)]
538pub struct VlogPassStats {
539 pub total_runs: u32,
540 pub successful_runs: u32,
541 pub total_changes: u64,
542 pub time_ms: u64,
543 pub iterations_used: u32,
544}
545impl VlogPassStats {
546 #[allow(dead_code)]
547 pub fn new() -> Self {
548 Self::default()
549 }
550 #[allow(dead_code)]
551 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
552 self.total_runs += 1;
553 self.successful_runs += 1;
554 self.total_changes += changes;
555 self.time_ms += time_ms;
556 self.iterations_used = iterations;
557 }
558 #[allow(dead_code)]
559 pub fn average_changes_per_run(&self) -> f64 {
560 if self.total_runs == 0 {
561 return 0.0;
562 }
563 self.total_changes as f64 / self.total_runs as f64
564 }
565 #[allow(dead_code)]
566 pub fn success_rate(&self) -> f64 {
567 if self.total_runs == 0 {
568 return 0.0;
569 }
570 self.successful_runs as f64 / self.total_runs as f64
571 }
572 #[allow(dead_code)]
573 pub fn format_summary(&self) -> String {
574 format!(
575 "Runs: {}/{}, Changes: {}, Time: {}ms",
576 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
577 )
578 }
579}
580#[allow(dead_code)]
581pub struct VlogPassRegistry {
582 pub(super) configs: Vec<VlogPassConfig>,
583 pub(super) stats: std::collections::HashMap<String, VlogPassStats>,
584}
585impl VlogPassRegistry {
586 #[allow(dead_code)]
587 pub fn new() -> Self {
588 VlogPassRegistry {
589 configs: Vec::new(),
590 stats: std::collections::HashMap::new(),
591 }
592 }
593 #[allow(dead_code)]
594 pub fn register(&mut self, config: VlogPassConfig) {
595 self.stats
596 .insert(config.pass_name.clone(), VlogPassStats::new());
597 self.configs.push(config);
598 }
599 #[allow(dead_code)]
600 pub fn enabled_passes(&self) -> Vec<&VlogPassConfig> {
601 self.configs.iter().filter(|c| c.enabled).collect()
602 }
603 #[allow(dead_code)]
604 pub fn get_stats(&self, name: &str) -> Option<&VlogPassStats> {
605 self.stats.get(name)
606 }
607 #[allow(dead_code)]
608 pub fn total_passes(&self) -> usize {
609 self.configs.len()
610 }
611 #[allow(dead_code)]
612 pub fn enabled_count(&self) -> usize {
613 self.enabled_passes().len()
614 }
615 #[allow(dead_code)]
616 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
617 if let Some(stats) = self.stats.get_mut(name) {
618 stats.record_run(changes, time_ms, iter);
619 }
620 }
621}
622#[allow(dead_code)]
624#[derive(Debug, Clone, PartialEq, Eq, Hash)]
625pub enum VerilogExtPassPhase {
626 Early,
627 Middle,
628 Late,
629 Finalize,
630}
631impl VerilogExtPassPhase {
632 #[allow(dead_code)]
633 pub fn is_early(&self) -> bool {
634 matches!(self, Self::Early)
635 }
636 #[allow(dead_code)]
637 pub fn is_middle(&self) -> bool {
638 matches!(self, Self::Middle)
639 }
640 #[allow(dead_code)]
641 pub fn is_late(&self) -> bool {
642 matches!(self, Self::Late)
643 }
644 #[allow(dead_code)]
645 pub fn is_finalize(&self) -> bool {
646 matches!(self, Self::Finalize)
647 }
648 #[allow(dead_code)]
649 pub fn order(&self) -> u32 {
650 match self {
651 Self::Early => 0,
652 Self::Middle => 1,
653 Self::Late => 2,
654 Self::Finalize => 3,
655 }
656 }
657 #[allow(dead_code)]
658 pub fn from_order(n: u32) -> Option<Self> {
659 match n {
660 0 => Some(Self::Early),
661 1 => Some(Self::Middle),
662 2 => Some(Self::Late),
663 3 => Some(Self::Finalize),
664 _ => None,
665 }
666 }
667}
668#[allow(dead_code)]
670#[derive(Debug, Clone)]
671pub struct VerilogExtPassConfig {
672 pub name: String,
673 pub phase: VerilogExtPassPhase,
674 pub enabled: bool,
675 pub max_iterations: usize,
676 pub debug: u32,
677 pub timeout_ms: Option<u64>,
678}
679impl VerilogExtPassConfig {
680 #[allow(dead_code)]
681 pub fn new(name: impl Into<String>) -> Self {
682 Self {
683 name: name.into(),
684 phase: VerilogExtPassPhase::Middle,
685 enabled: true,
686 max_iterations: 100,
687 debug: 0,
688 timeout_ms: None,
689 }
690 }
691 #[allow(dead_code)]
692 pub fn with_phase(mut self, phase: VerilogExtPassPhase) -> Self {
693 self.phase = phase;
694 self
695 }
696 #[allow(dead_code)]
697 pub fn with_max_iter(mut self, n: usize) -> Self {
698 self.max_iterations = n;
699 self
700 }
701 #[allow(dead_code)]
702 pub fn with_debug(mut self, d: u32) -> Self {
703 self.debug = d;
704 self
705 }
706 #[allow(dead_code)]
707 pub fn disabled(mut self) -> Self {
708 self.enabled = false;
709 self
710 }
711 #[allow(dead_code)]
712 pub fn with_timeout(mut self, ms: u64) -> Self {
713 self.timeout_ms = Some(ms);
714 self
715 }
716 #[allow(dead_code)]
717 pub fn is_debug_enabled(&self) -> bool {
718 self.debug > 0
719 }
720}
721#[allow(dead_code)]
722#[derive(Debug, Clone, PartialEq)]
723pub enum VlogPassPhase {
724 Analysis,
725 Transformation,
726 Verification,
727 Cleanup,
728}
729impl VlogPassPhase {
730 #[allow(dead_code)]
731 pub fn name(&self) -> &str {
732 match self {
733 VlogPassPhase::Analysis => "analysis",
734 VlogPassPhase::Transformation => "transformation",
735 VlogPassPhase::Verification => "verification",
736 VlogPassPhase::Cleanup => "cleanup",
737 }
738 }
739 #[allow(dead_code)]
740 pub fn is_modifying(&self) -> bool {
741 matches!(self, VlogPassPhase::Transformation | VlogPassPhase::Cleanup)
742 }
743}
744#[allow(dead_code)]
745#[derive(Debug, Clone)]
746pub struct VlogDepGraph {
747 pub(super) nodes: Vec<u32>,
748 pub(super) edges: Vec<(u32, u32)>,
749}
750impl VlogDepGraph {
751 #[allow(dead_code)]
752 pub fn new() -> Self {
753 VlogDepGraph {
754 nodes: Vec::new(),
755 edges: Vec::new(),
756 }
757 }
758 #[allow(dead_code)]
759 pub fn add_node(&mut self, id: u32) {
760 if !self.nodes.contains(&id) {
761 self.nodes.push(id);
762 }
763 }
764 #[allow(dead_code)]
765 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
766 self.add_node(dep);
767 self.add_node(dependent);
768 self.edges.push((dep, dependent));
769 }
770 #[allow(dead_code)]
771 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
772 self.edges
773 .iter()
774 .filter(|(d, _)| *d == node)
775 .map(|(_, dep)| *dep)
776 .collect()
777 }
778 #[allow(dead_code)]
779 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
780 self.edges
781 .iter()
782 .filter(|(_, dep)| *dep == node)
783 .map(|(d, _)| *d)
784 .collect()
785 }
786 #[allow(dead_code)]
787 pub fn topological_sort(&self) -> Vec<u32> {
788 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
789 for &n in &self.nodes {
790 in_degree.insert(n, 0);
791 }
792 for (_, dep) in &self.edges {
793 *in_degree.entry(*dep).or_insert(0) += 1;
794 }
795 let mut queue: std::collections::VecDeque<u32> = self
796 .nodes
797 .iter()
798 .filter(|&&n| in_degree[&n] == 0)
799 .copied()
800 .collect();
801 let mut result = Vec::new();
802 while let Some(node) = queue.pop_front() {
803 result.push(node);
804 for dep in self.dependents_of(node) {
805 let cnt = in_degree.entry(dep).or_insert(0);
806 *cnt = cnt.saturating_sub(1);
807 if *cnt == 0 {
808 queue.push_back(dep);
809 }
810 }
811 }
812 result
813 }
814 #[allow(dead_code)]
815 pub fn has_cycle(&self) -> bool {
816 self.topological_sort().len() < self.nodes.len()
817 }
818}
819#[allow(dead_code)]
820#[derive(Debug, Clone)]
821pub struct VlogAnalysisCache {
822 pub(super) entries: std::collections::HashMap<String, VlogCacheEntry>,
823 pub(super) max_size: usize,
824 pub(super) hits: u64,
825 pub(super) misses: u64,
826}
827impl VlogAnalysisCache {
828 #[allow(dead_code)]
829 pub fn new(max_size: usize) -> Self {
830 VlogAnalysisCache {
831 entries: std::collections::HashMap::new(),
832 max_size,
833 hits: 0,
834 misses: 0,
835 }
836 }
837 #[allow(dead_code)]
838 pub fn get(&mut self, key: &str) -> Option<&VlogCacheEntry> {
839 if self.entries.contains_key(key) {
840 self.hits += 1;
841 self.entries.get(key)
842 } else {
843 self.misses += 1;
844 None
845 }
846 }
847 #[allow(dead_code)]
848 pub fn insert(&mut self, key: String, data: Vec<u8>) {
849 if self.entries.len() >= self.max_size {
850 if let Some(oldest) = self.entries.keys().next().cloned() {
851 self.entries.remove(&oldest);
852 }
853 }
854 self.entries.insert(
855 key.clone(),
856 VlogCacheEntry {
857 key,
858 data,
859 timestamp: 0,
860 valid: true,
861 },
862 );
863 }
864 #[allow(dead_code)]
865 pub fn invalidate(&mut self, key: &str) {
866 if let Some(entry) = self.entries.get_mut(key) {
867 entry.valid = false;
868 }
869 }
870 #[allow(dead_code)]
871 pub fn clear(&mut self) {
872 self.entries.clear();
873 }
874 #[allow(dead_code)]
875 pub fn hit_rate(&self) -> f64 {
876 let total = self.hits + self.misses;
877 if total == 0 {
878 return 0.0;
879 }
880 self.hits as f64 / total as f64
881 }
882 #[allow(dead_code)]
883 pub fn size(&self) -> usize {
884 self.entries.len()
885 }
886}
887#[allow(dead_code)]
889#[derive(Debug, Clone)]
890pub struct VerilogX2Worklist {
891 pub(super) items: std::collections::VecDeque<usize>,
892 pub(super) present: Vec<bool>,
893}
894impl VerilogX2Worklist {
895 #[allow(dead_code)]
896 pub fn new(capacity: usize) -> Self {
897 Self {
898 items: std::collections::VecDeque::new(),
899 present: vec![false; capacity],
900 }
901 }
902 #[allow(dead_code)]
903 pub fn push(&mut self, id: usize) {
904 if id < self.present.len() && !self.present[id] {
905 self.present[id] = true;
906 self.items.push_back(id);
907 }
908 }
909 #[allow(dead_code)]
910 pub fn push_front(&mut self, id: usize) {
911 if id < self.present.len() && !self.present[id] {
912 self.present[id] = true;
913 self.items.push_front(id);
914 }
915 }
916 #[allow(dead_code)]
917 pub fn pop(&mut self) -> Option<usize> {
918 let id = self.items.pop_front()?;
919 if id < self.present.len() {
920 self.present[id] = false;
921 }
922 Some(id)
923 }
924 #[allow(dead_code)]
925 pub fn is_empty(&self) -> bool {
926 self.items.is_empty()
927 }
928 #[allow(dead_code)]
929 pub fn len(&self) -> usize {
930 self.items.len()
931 }
932 #[allow(dead_code)]
933 pub fn contains(&self, id: usize) -> bool {
934 id < self.present.len() && self.present[id]
935 }
936 #[allow(dead_code)]
937 pub fn drain_all(&mut self) -> Vec<usize> {
938 let v: Vec<usize> = self.items.drain(..).collect();
939 for &id in &v {
940 if id < self.present.len() {
941 self.present[id] = false;
942 }
943 }
944 v
945 }
946}
947#[allow(dead_code)]
949#[derive(Debug, Clone)]
950pub struct VerilogExtDomTree {
951 pub(super) idom: Vec<Option<usize>>,
952 pub(super) children: Vec<Vec<usize>>,
953 pub(super) depth: Vec<usize>,
954}
955impl VerilogExtDomTree {
956 #[allow(dead_code)]
957 pub fn new(n: usize) -> Self {
958 Self {
959 idom: vec![None; n],
960 children: vec![Vec::new(); n],
961 depth: vec![0; n],
962 }
963 }
964 #[allow(dead_code)]
965 pub fn set_idom(&mut self, node: usize, dom: usize) {
966 if node < self.idom.len() {
967 self.idom[node] = Some(dom);
968 if dom < self.children.len() {
969 self.children[dom].push(node);
970 }
971 self.depth[node] = if dom < self.depth.len() {
972 self.depth[dom] + 1
973 } else {
974 1
975 };
976 }
977 }
978 #[allow(dead_code)]
979 pub fn dominates(&self, a: usize, mut b: usize) -> bool {
980 if a == b {
981 return true;
982 }
983 let n = self.idom.len();
984 for _ in 0..n {
985 match self.idom.get(b).copied().flatten() {
986 None => return false,
987 Some(p) if p == a => return true,
988 Some(p) if p == b => return false,
989 Some(p) => b = p,
990 }
991 }
992 false
993 }
994 #[allow(dead_code)]
995 pub fn children_of(&self, n: usize) -> &[usize] {
996 self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
997 }
998 #[allow(dead_code)]
999 pub fn depth_of(&self, n: usize) -> usize {
1000 self.depth.get(n).copied().unwrap_or(0)
1001 }
1002 #[allow(dead_code)]
1003 pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
1004 let n = self.idom.len();
1005 for _ in 0..(2 * n) {
1006 if a == b {
1007 return a;
1008 }
1009 if self.depth_of(a) > self.depth_of(b) {
1010 a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
1011 } else {
1012 b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
1013 }
1014 }
1015 0
1016 }
1017}
1018#[allow(dead_code)]
1020#[derive(Debug, Clone)]
1021pub struct VerilogX2PassConfig {
1022 pub name: String,
1023 pub phase: VerilogX2PassPhase,
1024 pub enabled: bool,
1025 pub max_iterations: usize,
1026 pub debug: u32,
1027 pub timeout_ms: Option<u64>,
1028}
1029impl VerilogX2PassConfig {
1030 #[allow(dead_code)]
1031 pub fn new(name: impl Into<String>) -> Self {
1032 Self {
1033 name: name.into(),
1034 phase: VerilogX2PassPhase::Middle,
1035 enabled: true,
1036 max_iterations: 100,
1037 debug: 0,
1038 timeout_ms: None,
1039 }
1040 }
1041 #[allow(dead_code)]
1042 pub fn with_phase(mut self, phase: VerilogX2PassPhase) -> Self {
1043 self.phase = phase;
1044 self
1045 }
1046 #[allow(dead_code)]
1047 pub fn with_max_iter(mut self, n: usize) -> Self {
1048 self.max_iterations = n;
1049 self
1050 }
1051 #[allow(dead_code)]
1052 pub fn with_debug(mut self, d: u32) -> Self {
1053 self.debug = d;
1054 self
1055 }
1056 #[allow(dead_code)]
1057 pub fn disabled(mut self) -> Self {
1058 self.enabled = false;
1059 self
1060 }
1061 #[allow(dead_code)]
1062 pub fn with_timeout(mut self, ms: u64) -> Self {
1063 self.timeout_ms = Some(ms);
1064 self
1065 }
1066 #[allow(dead_code)]
1067 pub fn is_debug_enabled(&self) -> bool {
1068 self.debug > 0
1069 }
1070}
1071#[allow(dead_code)]
1073#[derive(Debug, Clone, Default)]
1074pub struct VerilogExtLiveness {
1075 pub live_in: Vec<Vec<usize>>,
1076 pub live_out: Vec<Vec<usize>>,
1077 pub defs: Vec<Vec<usize>>,
1078 pub uses: Vec<Vec<usize>>,
1079}
1080impl VerilogExtLiveness {
1081 #[allow(dead_code)]
1082 pub fn new(n: usize) -> Self {
1083 Self {
1084 live_in: vec![Vec::new(); n],
1085 live_out: vec![Vec::new(); n],
1086 defs: vec![Vec::new(); n],
1087 uses: vec![Vec::new(); n],
1088 }
1089 }
1090 #[allow(dead_code)]
1091 pub fn live_in(&self, b: usize, v: usize) -> bool {
1092 self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1093 }
1094 #[allow(dead_code)]
1095 pub fn live_out(&self, b: usize, v: usize) -> bool {
1096 self.live_out
1097 .get(b)
1098 .map(|s| s.contains(&v))
1099 .unwrap_or(false)
1100 }
1101 #[allow(dead_code)]
1102 pub fn add_def(&mut self, b: usize, v: usize) {
1103 if let Some(s) = self.defs.get_mut(b) {
1104 if !s.contains(&v) {
1105 s.push(v);
1106 }
1107 }
1108 }
1109 #[allow(dead_code)]
1110 pub fn add_use(&mut self, b: usize, v: usize) {
1111 if let Some(s) = self.uses.get_mut(b) {
1112 if !s.contains(&v) {
1113 s.push(v);
1114 }
1115 }
1116 }
1117 #[allow(dead_code)]
1118 pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
1119 self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1120 }
1121 #[allow(dead_code)]
1122 pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
1123 self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1124 }
1125}
1126#[allow(dead_code)]
1128#[derive(Debug, Clone)]
1129pub struct VerilogX2DepGraph {
1130 pub(super) n: usize,
1131 pub(super) adj: Vec<Vec<usize>>,
1132 pub(super) rev: Vec<Vec<usize>>,
1133 pub(super) edge_count: usize,
1134}
1135impl VerilogX2DepGraph {
1136 #[allow(dead_code)]
1137 pub fn new(n: usize) -> Self {
1138 Self {
1139 n,
1140 adj: vec![Vec::new(); n],
1141 rev: vec![Vec::new(); n],
1142 edge_count: 0,
1143 }
1144 }
1145 #[allow(dead_code)]
1146 pub fn add_edge(&mut self, from: usize, to: usize) {
1147 if from < self.n && to < self.n {
1148 if !self.adj[from].contains(&to) {
1149 self.adj[from].push(to);
1150 self.rev[to].push(from);
1151 self.edge_count += 1;
1152 }
1153 }
1154 }
1155 #[allow(dead_code)]
1156 pub fn succs(&self, n: usize) -> &[usize] {
1157 self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1158 }
1159 #[allow(dead_code)]
1160 pub fn preds(&self, n: usize) -> &[usize] {
1161 self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1162 }
1163 #[allow(dead_code)]
1164 pub fn topo_sort(&self) -> Option<Vec<usize>> {
1165 let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
1166 let mut q: std::collections::VecDeque<usize> =
1167 (0..self.n).filter(|&i| deg[i] == 0).collect();
1168 let mut out = Vec::with_capacity(self.n);
1169 while let Some(u) = q.pop_front() {
1170 out.push(u);
1171 for &v in &self.adj[u] {
1172 deg[v] -= 1;
1173 if deg[v] == 0 {
1174 q.push_back(v);
1175 }
1176 }
1177 }
1178 if out.len() == self.n {
1179 Some(out)
1180 } else {
1181 None
1182 }
1183 }
1184 #[allow(dead_code)]
1185 pub fn has_cycle(&self) -> bool {
1186 self.topo_sort().is_none()
1187 }
1188 #[allow(dead_code)]
1189 pub fn reachable(&self, start: usize) -> Vec<usize> {
1190 let mut vis = vec![false; self.n];
1191 let mut stk = vec![start];
1192 let mut out = Vec::new();
1193 while let Some(u) = stk.pop() {
1194 if u < self.n && !vis[u] {
1195 vis[u] = true;
1196 out.push(u);
1197 for &v in &self.adj[u] {
1198 if !vis[v] {
1199 stk.push(v);
1200 }
1201 }
1202 }
1203 }
1204 out
1205 }
1206 #[allow(dead_code)]
1207 pub fn scc(&self) -> Vec<Vec<usize>> {
1208 let mut visited = vec![false; self.n];
1209 let mut order = Vec::new();
1210 for i in 0..self.n {
1211 if !visited[i] {
1212 let mut stk = vec![(i, 0usize)];
1213 while let Some((u, idx)) = stk.last_mut() {
1214 if !visited[*u] {
1215 visited[*u] = true;
1216 }
1217 if *idx < self.adj[*u].len() {
1218 let v = self.adj[*u][*idx];
1219 *idx += 1;
1220 if !visited[v] {
1221 stk.push((v, 0));
1222 }
1223 } else {
1224 order.push(*u);
1225 stk.pop();
1226 }
1227 }
1228 }
1229 }
1230 let mut comp = vec![usize::MAX; self.n];
1231 let mut components: Vec<Vec<usize>> = Vec::new();
1232 for &start in order.iter().rev() {
1233 if comp[start] == usize::MAX {
1234 let cid = components.len();
1235 let mut component = Vec::new();
1236 let mut stk = vec![start];
1237 while let Some(u) = stk.pop() {
1238 if comp[u] == usize::MAX {
1239 comp[u] = cid;
1240 component.push(u);
1241 for &v in &self.rev[u] {
1242 if comp[v] == usize::MAX {
1243 stk.push(v);
1244 }
1245 }
1246 }
1247 }
1248 components.push(component);
1249 }
1250 }
1251 components
1252 }
1253 #[allow(dead_code)]
1254 pub fn node_count(&self) -> usize {
1255 self.n
1256 }
1257 #[allow(dead_code)]
1258 pub fn edge_count(&self) -> usize {
1259 self.edge_count
1260 }
1261}
1262#[allow(dead_code)]
1264#[derive(Debug)]
1265pub struct VerilogExtCache {
1266 pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
1267 pub(super) cap: usize,
1268 pub(super) total_hits: u64,
1269 pub(super) total_misses: u64,
1270}
1271impl VerilogExtCache {
1272 #[allow(dead_code)]
1273 pub fn new(cap: usize) -> Self {
1274 Self {
1275 entries: Vec::new(),
1276 cap,
1277 total_hits: 0,
1278 total_misses: 0,
1279 }
1280 }
1281 #[allow(dead_code)]
1282 pub fn get(&mut self, key: u64) -> Option<&[u8]> {
1283 for e in self.entries.iter_mut() {
1284 if e.0 == key && e.2 {
1285 e.3 += 1;
1286 self.total_hits += 1;
1287 return Some(&e.1);
1288 }
1289 }
1290 self.total_misses += 1;
1291 None
1292 }
1293 #[allow(dead_code)]
1294 pub fn put(&mut self, key: u64, data: Vec<u8>) {
1295 if self.entries.len() >= self.cap {
1296 self.entries.retain(|e| e.2);
1297 if self.entries.len() >= self.cap {
1298 self.entries.remove(0);
1299 }
1300 }
1301 self.entries.push((key, data, true, 0));
1302 }
1303 #[allow(dead_code)]
1304 pub fn invalidate(&mut self) {
1305 for e in self.entries.iter_mut() {
1306 e.2 = false;
1307 }
1308 }
1309 #[allow(dead_code)]
1310 pub fn hit_rate(&self) -> f64 {
1311 let t = self.total_hits + self.total_misses;
1312 if t == 0 {
1313 0.0
1314 } else {
1315 self.total_hits as f64 / t as f64
1316 }
1317 }
1318 #[allow(dead_code)]
1319 pub fn live_count(&self) -> usize {
1320 self.entries.iter().filter(|e| e.2).count()
1321 }
1322}
1323#[derive(Debug, Clone, PartialEq)]
1325pub enum VerilogPort {
1326 Input(String, u32),
1328 Output(String, u32),
1330 InOut(String, u32),
1332}
1333impl VerilogPort {
1334 pub fn name(&self) -> &str {
1336 match self {
1337 VerilogPort::Input(n, _) => n,
1338 VerilogPort::Output(n, _) => n,
1339 VerilogPort::InOut(n, _) => n,
1340 }
1341 }
1342 pub fn width(&self) -> u32 {
1344 match self {
1345 VerilogPort::Input(_, w) => *w,
1346 VerilogPort::Output(_, w) => *w,
1347 VerilogPort::InOut(_, w) => *w,
1348 }
1349 }
1350 pub fn direction(&self) -> &'static str {
1352 match self {
1353 VerilogPort::Input(..) => "input",
1354 VerilogPort::Output(..) => "output",
1355 VerilogPort::InOut(..) => "inout",
1356 }
1357 }
1358}
1359#[allow(dead_code)]
1361#[derive(Debug, Clone, Default)]
1362pub struct VerilogExtConstFolder {
1363 pub(super) folds: usize,
1364 pub(super) failures: usize,
1365 pub(super) enabled: bool,
1366}
1367impl VerilogExtConstFolder {
1368 #[allow(dead_code)]
1369 pub fn new() -> Self {
1370 Self {
1371 folds: 0,
1372 failures: 0,
1373 enabled: true,
1374 }
1375 }
1376 #[allow(dead_code)]
1377 pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1378 self.folds += 1;
1379 a.checked_add(b)
1380 }
1381 #[allow(dead_code)]
1382 pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1383 self.folds += 1;
1384 a.checked_sub(b)
1385 }
1386 #[allow(dead_code)]
1387 pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1388 self.folds += 1;
1389 a.checked_mul(b)
1390 }
1391 #[allow(dead_code)]
1392 pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1393 if b == 0 {
1394 self.failures += 1;
1395 None
1396 } else {
1397 self.folds += 1;
1398 a.checked_div(b)
1399 }
1400 }
1401 #[allow(dead_code)]
1402 pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1403 if b == 0 {
1404 self.failures += 1;
1405 None
1406 } else {
1407 self.folds += 1;
1408 a.checked_rem(b)
1409 }
1410 }
1411 #[allow(dead_code)]
1412 pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
1413 self.folds += 1;
1414 a.checked_neg()
1415 }
1416 #[allow(dead_code)]
1417 pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1418 if s >= 64 {
1419 self.failures += 1;
1420 None
1421 } else {
1422 self.folds += 1;
1423 a.checked_shl(s)
1424 }
1425 }
1426 #[allow(dead_code)]
1427 pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1428 if s >= 64 {
1429 self.failures += 1;
1430 None
1431 } else {
1432 self.folds += 1;
1433 a.checked_shr(s)
1434 }
1435 }
1436 #[allow(dead_code)]
1437 pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
1438 self.folds += 1;
1439 a & b
1440 }
1441 #[allow(dead_code)]
1442 pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
1443 self.folds += 1;
1444 a | b
1445 }
1446 #[allow(dead_code)]
1447 pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
1448 self.folds += 1;
1449 a ^ b
1450 }
1451 #[allow(dead_code)]
1452 pub fn not_i64(&mut self, a: i64) -> i64 {
1453 self.folds += 1;
1454 !a
1455 }
1456 #[allow(dead_code)]
1457 pub fn fold_count(&self) -> usize {
1458 self.folds
1459 }
1460 #[allow(dead_code)]
1461 pub fn failure_count(&self) -> usize {
1462 self.failures
1463 }
1464 #[allow(dead_code)]
1465 pub fn enable(&mut self) {
1466 self.enabled = true;
1467 }
1468 #[allow(dead_code)]
1469 pub fn disable(&mut self) {
1470 self.enabled = false;
1471 }
1472 #[allow(dead_code)]
1473 pub fn is_enabled(&self) -> bool {
1474 self.enabled
1475 }
1476}
1477#[allow(dead_code)]
1479#[derive(Debug)]
1480pub struct VerilogX2Cache {
1481 pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
1482 pub(super) cap: usize,
1483 pub(super) total_hits: u64,
1484 pub(super) total_misses: u64,
1485}
1486impl VerilogX2Cache {
1487 #[allow(dead_code)]
1488 pub fn new(cap: usize) -> Self {
1489 Self {
1490 entries: Vec::new(),
1491 cap,
1492 total_hits: 0,
1493 total_misses: 0,
1494 }
1495 }
1496 #[allow(dead_code)]
1497 pub fn get(&mut self, key: u64) -> Option<&[u8]> {
1498 for e in self.entries.iter_mut() {
1499 if e.0 == key && e.2 {
1500 e.3 += 1;
1501 self.total_hits += 1;
1502 return Some(&e.1);
1503 }
1504 }
1505 self.total_misses += 1;
1506 None
1507 }
1508 #[allow(dead_code)]
1509 pub fn put(&mut self, key: u64, data: Vec<u8>) {
1510 if self.entries.len() >= self.cap {
1511 self.entries.retain(|e| e.2);
1512 if self.entries.len() >= self.cap {
1513 self.entries.remove(0);
1514 }
1515 }
1516 self.entries.push((key, data, true, 0));
1517 }
1518 #[allow(dead_code)]
1519 pub fn invalidate(&mut self) {
1520 for e in self.entries.iter_mut() {
1521 e.2 = false;
1522 }
1523 }
1524 #[allow(dead_code)]
1525 pub fn hit_rate(&self) -> f64 {
1526 let t = self.total_hits + self.total_misses;
1527 if t == 0 {
1528 0.0
1529 } else {
1530 self.total_hits as f64 / t as f64
1531 }
1532 }
1533 #[allow(dead_code)]
1534 pub fn live_count(&self) -> usize {
1535 self.entries.iter().filter(|e| e.2).count()
1536 }
1537}
1538#[allow(dead_code)]
1540#[derive(Debug, Clone, Default)]
1541pub struct VerilogX2ConstFolder {
1542 pub(super) folds: usize,
1543 pub(super) failures: usize,
1544 pub(super) enabled: bool,
1545}
1546impl VerilogX2ConstFolder {
1547 #[allow(dead_code)]
1548 pub fn new() -> Self {
1549 Self {
1550 folds: 0,
1551 failures: 0,
1552 enabled: true,
1553 }
1554 }
1555 #[allow(dead_code)]
1556 pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1557 self.folds += 1;
1558 a.checked_add(b)
1559 }
1560 #[allow(dead_code)]
1561 pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1562 self.folds += 1;
1563 a.checked_sub(b)
1564 }
1565 #[allow(dead_code)]
1566 pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1567 self.folds += 1;
1568 a.checked_mul(b)
1569 }
1570 #[allow(dead_code)]
1571 pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1572 if b == 0 {
1573 self.failures += 1;
1574 None
1575 } else {
1576 self.folds += 1;
1577 a.checked_div(b)
1578 }
1579 }
1580 #[allow(dead_code)]
1581 pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1582 if b == 0 {
1583 self.failures += 1;
1584 None
1585 } else {
1586 self.folds += 1;
1587 a.checked_rem(b)
1588 }
1589 }
1590 #[allow(dead_code)]
1591 pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
1592 self.folds += 1;
1593 a.checked_neg()
1594 }
1595 #[allow(dead_code)]
1596 pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1597 if s >= 64 {
1598 self.failures += 1;
1599 None
1600 } else {
1601 self.folds += 1;
1602 a.checked_shl(s)
1603 }
1604 }
1605 #[allow(dead_code)]
1606 pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1607 if s >= 64 {
1608 self.failures += 1;
1609 None
1610 } else {
1611 self.folds += 1;
1612 a.checked_shr(s)
1613 }
1614 }
1615 #[allow(dead_code)]
1616 pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
1617 self.folds += 1;
1618 a & b
1619 }
1620 #[allow(dead_code)]
1621 pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
1622 self.folds += 1;
1623 a | b
1624 }
1625 #[allow(dead_code)]
1626 pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
1627 self.folds += 1;
1628 a ^ b
1629 }
1630 #[allow(dead_code)]
1631 pub fn not_i64(&mut self, a: i64) -> i64 {
1632 self.folds += 1;
1633 !a
1634 }
1635 #[allow(dead_code)]
1636 pub fn fold_count(&self) -> usize {
1637 self.folds
1638 }
1639 #[allow(dead_code)]
1640 pub fn failure_count(&self) -> usize {
1641 self.failures
1642 }
1643 #[allow(dead_code)]
1644 pub fn enable(&mut self) {
1645 self.enabled = true;
1646 }
1647 #[allow(dead_code)]
1648 pub fn disable(&mut self) {
1649 self.enabled = false;
1650 }
1651 #[allow(dead_code)]
1652 pub fn is_enabled(&self) -> bool {
1653 self.enabled
1654 }
1655}
1656#[allow(dead_code)]
1657#[derive(Debug, Clone)]
1658pub struct VlogCacheEntry {
1659 pub key: String,
1660 pub data: Vec<u8>,
1661 pub timestamp: u64,
1662 pub valid: bool,
1663}
1664#[allow(dead_code)]
1665#[derive(Debug, Clone)]
1666pub struct VlogDominatorTree {
1667 pub idom: Vec<Option<u32>>,
1668 pub dom_children: Vec<Vec<u32>>,
1669 pub dom_depth: Vec<u32>,
1670}
1671impl VlogDominatorTree {
1672 #[allow(dead_code)]
1673 pub fn new(size: usize) -> Self {
1674 VlogDominatorTree {
1675 idom: vec![None; size],
1676 dom_children: vec![Vec::new(); size],
1677 dom_depth: vec![0; size],
1678 }
1679 }
1680 #[allow(dead_code)]
1681 pub fn set_idom(&mut self, node: usize, idom: u32) {
1682 self.idom[node] = Some(idom);
1683 }
1684 #[allow(dead_code)]
1685 pub fn dominates(&self, a: usize, b: usize) -> bool {
1686 if a == b {
1687 return true;
1688 }
1689 let mut cur = b;
1690 loop {
1691 match self.idom[cur] {
1692 Some(parent) if parent as usize == a => return true,
1693 Some(parent) if parent as usize == cur => return false,
1694 Some(parent) => cur = parent as usize,
1695 None => return false,
1696 }
1697 }
1698 }
1699 #[allow(dead_code)]
1700 pub fn depth(&self, node: usize) -> u32 {
1701 self.dom_depth.get(node).copied().unwrap_or(0)
1702 }
1703}
1704#[allow(dead_code)]
1705pub struct VlogConstantFoldingHelper;
1706impl VlogConstantFoldingHelper {
1707 #[allow(dead_code)]
1708 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
1709 a.checked_add(b)
1710 }
1711 #[allow(dead_code)]
1712 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
1713 a.checked_sub(b)
1714 }
1715 #[allow(dead_code)]
1716 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
1717 a.checked_mul(b)
1718 }
1719 #[allow(dead_code)]
1720 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
1721 if b == 0 {
1722 None
1723 } else {
1724 a.checked_div(b)
1725 }
1726 }
1727 #[allow(dead_code)]
1728 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
1729 a + b
1730 }
1731 #[allow(dead_code)]
1732 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
1733 a * b
1734 }
1735 #[allow(dead_code)]
1736 pub fn fold_neg_i64(a: i64) -> Option<i64> {
1737 a.checked_neg()
1738 }
1739 #[allow(dead_code)]
1740 pub fn fold_not_bool(a: bool) -> bool {
1741 !a
1742 }
1743 #[allow(dead_code)]
1744 pub fn fold_and_bool(a: bool, b: bool) -> bool {
1745 a && b
1746 }
1747 #[allow(dead_code)]
1748 pub fn fold_or_bool(a: bool, b: bool) -> bool {
1749 a || b
1750 }
1751 #[allow(dead_code)]
1752 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
1753 a.checked_shl(b)
1754 }
1755 #[allow(dead_code)]
1756 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
1757 a.checked_shr(b)
1758 }
1759 #[allow(dead_code)]
1760 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
1761 if b == 0 {
1762 None
1763 } else {
1764 Some(a % b)
1765 }
1766 }
1767 #[allow(dead_code)]
1768 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
1769 a & b
1770 }
1771 #[allow(dead_code)]
1772 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
1773 a | b
1774 }
1775 #[allow(dead_code)]
1776 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
1777 a ^ b
1778 }
1779 #[allow(dead_code)]
1780 pub fn fold_bitnot_i64(a: i64) -> i64 {
1781 !a
1782 }
1783}
1784#[derive(Debug, Clone, PartialEq)]
1786pub enum VerilogType {
1787 Wire(u32),
1789 Reg(u32),
1791 Logic(u32),
1793 Integer,
1795 Real,
1797}
1798#[allow(dead_code)]
1799#[derive(Debug, Clone)]
1800pub struct VlogWorklist {
1801 pub(super) items: std::collections::VecDeque<u32>,
1802 pub(super) in_worklist: std::collections::HashSet<u32>,
1803}
1804impl VlogWorklist {
1805 #[allow(dead_code)]
1806 pub fn new() -> Self {
1807 VlogWorklist {
1808 items: std::collections::VecDeque::new(),
1809 in_worklist: std::collections::HashSet::new(),
1810 }
1811 }
1812 #[allow(dead_code)]
1813 pub fn push(&mut self, item: u32) -> bool {
1814 if self.in_worklist.insert(item) {
1815 self.items.push_back(item);
1816 true
1817 } else {
1818 false
1819 }
1820 }
1821 #[allow(dead_code)]
1822 pub fn pop(&mut self) -> Option<u32> {
1823 let item = self.items.pop_front()?;
1824 self.in_worklist.remove(&item);
1825 Some(item)
1826 }
1827 #[allow(dead_code)]
1828 pub fn is_empty(&self) -> bool {
1829 self.items.is_empty()
1830 }
1831 #[allow(dead_code)]
1832 pub fn len(&self) -> usize {
1833 self.items.len()
1834 }
1835 #[allow(dead_code)]
1836 pub fn contains(&self, item: u32) -> bool {
1837 self.in_worklist.contains(&item)
1838 }
1839}
1840#[derive(Debug, Clone)]
1842pub struct VerilogBackend {
1843 pub system_verilog: bool,
1845}
1846impl VerilogBackend {
1847 pub fn new(system_verilog: bool) -> Self {
1852 VerilogBackend { system_verilog }
1853 }
1854 pub fn emit_type(&self, ty: &VerilogType) -> String {
1858 match ty {
1859 VerilogType::Logic(w) if !self.system_verilog => VerilogType::Reg(*w).to_string(),
1860 other => other.to_string(),
1861 }
1862 }
1863 pub fn emit_expr(&self, expr: &VerilogExpr) -> String {
1865 expr.to_string()
1866 }
1867 pub fn emit_module(&self, module: &VerilogModule) -> String {
1869 let mut out = String::new();
1870 let ext = if self.system_verilog { "sv" } else { "v" };
1871 out.push_str(&format!(
1872 "// Generated by OxiLean VerilogBackend (.{ext})\n\n"
1873 ));
1874 out.push_str(&format!("module {}", module.name));
1875 if !module.params.is_empty() {
1876 out.push_str(" #(\n");
1877 for (i, (pname, default)) in module.params.iter().enumerate() {
1878 let comma = if i + 1 < module.params.len() { "," } else { "" };
1879 out.push_str(&format!(" parameter {pname} = {default}{comma}\n"));
1880 }
1881 out.push(')');
1882 }
1883 if !module.ports.is_empty() {
1884 out.push_str(" (\n");
1885 for (i, port) in module.ports.iter().enumerate() {
1886 let comma = if i + 1 < module.ports.len() { "," } else { "" };
1887 let width_str = range_suffix(port.width());
1888 let type_kw = if self.system_verilog
1889 && matches!(port, VerilogPort::Input(..) | VerilogPort::Output(..))
1890 {
1891 "logic"
1892 } else {
1893 match port {
1894 VerilogPort::Input(..) => "wire",
1895 VerilogPort::Output(..) => "reg",
1896 VerilogPort::InOut(..) => "wire",
1897 }
1898 };
1899 out.push_str(&format!(
1900 " {dir} {type_kw}{width_str} {name}{comma}\n",
1901 dir = port.direction(),
1902 width_str = if width_str.is_empty() {
1903 String::new()
1904 } else {
1905 format!(" {width_str}")
1906 },
1907 name = port.name(),
1908 ));
1909 }
1910 out.push(')');
1911 }
1912 out.push_str(";\n\n");
1913 for stmt in &module.body {
1914 out.push_str(" ");
1915 out.push_str(stmt);
1916 out.push('\n');
1917 }
1918 out.push_str("\nendmodule\n");
1919 out
1920 }
1921 pub fn always_block(&self, sensitivity: &str, body: &str) -> String {
1930 if self.system_verilog {
1931 if sensitivity == "comb" {
1932 return format!("always_comb begin\n {body}\nend");
1933 }
1934 if let Some(rest) = sensitivity.strip_prefix("ff ") {
1935 return format!("always_ff @({rest}) begin\n {body}\nend");
1936 }
1937 }
1938 format!("always @({sensitivity}) begin\n {body}\nend")
1939 }
1940 pub fn assign_stmt(&self, lhs: &str, rhs: &str) -> String {
1942 format!("assign {lhs} = {rhs};")
1943 }
1944 pub fn nonblocking_assign(&self, lhs: &str, rhs: &str) -> String {
1946 format!("{lhs} <= {rhs};")
1947 }
1948 pub fn blocking_assign(&self, lhs: &str, rhs: &str) -> String {
1950 format!("{lhs} = {rhs};")
1951 }
1952 pub fn if_else(&self, cond: &str, then_body: &str, else_body: Option<&str>) -> String {
1954 match else_body {
1955 Some(eb) => {
1956 format!(
1957 "if ({cond}) begin\n {then_body}\n end else begin\n {eb}\n end"
1958 )
1959 }
1960 None => format!("if ({cond}) begin\n {then_body}\n end"),
1961 }
1962 }
1963 pub fn initial_block(&self, body: &str) -> String {
1965 format!("initial begin\n {body}\nend")
1966 }
1967 pub fn declare_signal(&self, ty: &VerilogType, name: &str) -> String {
1969 format!("{} {name};", self.emit_type(ty))
1970 }
1971 pub fn instantiate(
1975 &self,
1976 module_name: &str,
1977 instance_name: &str,
1978 port_map: &[(&str, &str)],
1979 ) -> String {
1980 let mut s = format!("{module_name} {instance_name} (\n");
1981 for (i, (formal, actual)) in port_map.iter().enumerate() {
1982 let comma = if i + 1 < port_map.len() { "," } else { "" };
1983 s.push_str(&format!(" .{formal}({actual}){comma}\n"));
1984 }
1985 s.push_str(");");
1986 s
1987 }
1988 pub fn sys_task(&self, task: &str, fmt_str: &str, args: &[&str]) -> String {
1990 if args.is_empty() {
1991 format!("{task}(\"{fmt_str}\");")
1992 } else {
1993 let arg_str = args.join(", ");
1994 format!("{task}(\"{fmt_str}\", {arg_str});")
1995 }
1996 }
1997}
1998#[allow(dead_code)]
2000#[derive(Debug, Clone, Default)]
2001pub struct VerilogX2Liveness {
2002 pub live_in: Vec<Vec<usize>>,
2003 pub live_out: Vec<Vec<usize>>,
2004 pub defs: Vec<Vec<usize>>,
2005 pub uses: Vec<Vec<usize>>,
2006}
2007impl VerilogX2Liveness {
2008 #[allow(dead_code)]
2009 pub fn new(n: usize) -> Self {
2010 Self {
2011 live_in: vec![Vec::new(); n],
2012 live_out: vec![Vec::new(); n],
2013 defs: vec![Vec::new(); n],
2014 uses: vec![Vec::new(); n],
2015 }
2016 }
2017 #[allow(dead_code)]
2018 pub fn live_in(&self, b: usize, v: usize) -> bool {
2019 self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2020 }
2021 #[allow(dead_code)]
2022 pub fn live_out(&self, b: usize, v: usize) -> bool {
2023 self.live_out
2024 .get(b)
2025 .map(|s| s.contains(&v))
2026 .unwrap_or(false)
2027 }
2028 #[allow(dead_code)]
2029 pub fn add_def(&mut self, b: usize, v: usize) {
2030 if let Some(s) = self.defs.get_mut(b) {
2031 if !s.contains(&v) {
2032 s.push(v);
2033 }
2034 }
2035 }
2036 #[allow(dead_code)]
2037 pub fn add_use(&mut self, b: usize, v: usize) {
2038 if let Some(s) = self.uses.get_mut(b) {
2039 if !s.contains(&v) {
2040 s.push(v);
2041 }
2042 }
2043 }
2044 #[allow(dead_code)]
2045 pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
2046 self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2047 }
2048 #[allow(dead_code)]
2049 pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
2050 self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
2051 }
2052}
2053#[derive(Debug, Clone, PartialEq)]
2055pub enum VerilogExpr {
2056 Lit(u64, u32),
2058 Var(String),
2060 BinOp(Box<VerilogExpr>, String, Box<VerilogExpr>),
2062 UnOp(String, Box<VerilogExpr>),
2064 Concat(Vec<VerilogExpr>),
2066 Replicate(u32, Box<VerilogExpr>),
2068 Index(Box<VerilogExpr>, u32),
2070 Slice(Box<VerilogExpr>, u32, u32),
2072 Ternary(Box<VerilogExpr>, Box<VerilogExpr>, Box<VerilogExpr>),
2074 Call(String, Vec<VerilogExpr>),
2076}
2077#[allow(dead_code)]
2079#[derive(Debug, Clone)]
2080pub struct VerilogExtWorklist {
2081 pub(super) items: std::collections::VecDeque<usize>,
2082 pub(super) present: Vec<bool>,
2083}
2084impl VerilogExtWorklist {
2085 #[allow(dead_code)]
2086 pub fn new(capacity: usize) -> Self {
2087 Self {
2088 items: std::collections::VecDeque::new(),
2089 present: vec![false; capacity],
2090 }
2091 }
2092 #[allow(dead_code)]
2093 pub fn push(&mut self, id: usize) {
2094 if id < self.present.len() && !self.present[id] {
2095 self.present[id] = true;
2096 self.items.push_back(id);
2097 }
2098 }
2099 #[allow(dead_code)]
2100 pub fn push_front(&mut self, id: usize) {
2101 if id < self.present.len() && !self.present[id] {
2102 self.present[id] = true;
2103 self.items.push_front(id);
2104 }
2105 }
2106 #[allow(dead_code)]
2107 pub fn pop(&mut self) -> Option<usize> {
2108 let id = self.items.pop_front()?;
2109 if id < self.present.len() {
2110 self.present[id] = false;
2111 }
2112 Some(id)
2113 }
2114 #[allow(dead_code)]
2115 pub fn is_empty(&self) -> bool {
2116 self.items.is_empty()
2117 }
2118 #[allow(dead_code)]
2119 pub fn len(&self) -> usize {
2120 self.items.len()
2121 }
2122 #[allow(dead_code)]
2123 pub fn contains(&self, id: usize) -> bool {
2124 id < self.present.len() && self.present[id]
2125 }
2126 #[allow(dead_code)]
2127 pub fn drain_all(&mut self) -> Vec<usize> {
2128 let v: Vec<usize> = self.items.drain(..).collect();
2129 for &id in &v {
2130 if id < self.present.len() {
2131 self.present[id] = false;
2132 }
2133 }
2134 v
2135 }
2136}
2137#[allow(dead_code)]
2139#[derive(Debug, Default)]
2140pub struct VerilogX2PassRegistry {
2141 pub(super) configs: Vec<VerilogX2PassConfig>,
2142 pub(super) stats: Vec<VerilogX2PassStats>,
2143}
2144impl VerilogX2PassRegistry {
2145 #[allow(dead_code)]
2146 pub fn new() -> Self {
2147 Self::default()
2148 }
2149 #[allow(dead_code)]
2150 pub fn register(&mut self, c: VerilogX2PassConfig) {
2151 self.stats.push(VerilogX2PassStats::new());
2152 self.configs.push(c);
2153 }
2154 #[allow(dead_code)]
2155 pub fn len(&self) -> usize {
2156 self.configs.len()
2157 }
2158 #[allow(dead_code)]
2159 pub fn is_empty(&self) -> bool {
2160 self.configs.is_empty()
2161 }
2162 #[allow(dead_code)]
2163 pub fn get(&self, i: usize) -> Option<&VerilogX2PassConfig> {
2164 self.configs.get(i)
2165 }
2166 #[allow(dead_code)]
2167 pub fn get_stats(&self, i: usize) -> Option<&VerilogX2PassStats> {
2168 self.stats.get(i)
2169 }
2170 #[allow(dead_code)]
2171 pub fn enabled_passes(&self) -> Vec<&VerilogX2PassConfig> {
2172 self.configs.iter().filter(|c| c.enabled).collect()
2173 }
2174 #[allow(dead_code)]
2175 pub fn passes_in_phase(&self, ph: &VerilogX2PassPhase) -> Vec<&VerilogX2PassConfig> {
2176 self.configs
2177 .iter()
2178 .filter(|c| c.enabled && &c.phase == ph)
2179 .collect()
2180 }
2181 #[allow(dead_code)]
2182 pub fn total_nodes_visited(&self) -> usize {
2183 self.stats.iter().map(|s| s.nodes_visited).sum()
2184 }
2185 #[allow(dead_code)]
2186 pub fn any_changed(&self) -> bool {
2187 self.stats.iter().any(|s| s.changed)
2188 }
2189}