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