1use std::collections::HashMap;
6
7use std::collections::{HashSet, VecDeque};
8
9#[allow(dead_code)]
10#[derive(Debug, Clone)]
11pub struct ChplDepGraph {
12 pub(super) nodes: Vec<u32>,
13 pub(super) edges: Vec<(u32, u32)>,
14}
15impl ChplDepGraph {
16 #[allow(dead_code)]
17 pub fn new() -> Self {
18 ChplDepGraph {
19 nodes: Vec::new(),
20 edges: Vec::new(),
21 }
22 }
23 #[allow(dead_code)]
24 pub fn add_node(&mut self, id: u32) {
25 if !self.nodes.contains(&id) {
26 self.nodes.push(id);
27 }
28 }
29 #[allow(dead_code)]
30 pub fn add_dep(&mut self, dep: u32, dependent: u32) {
31 self.add_node(dep);
32 self.add_node(dependent);
33 self.edges.push((dep, dependent));
34 }
35 #[allow(dead_code)]
36 pub fn dependents_of(&self, node: u32) -> Vec<u32> {
37 self.edges
38 .iter()
39 .filter(|(d, _)| *d == node)
40 .map(|(_, dep)| *dep)
41 .collect()
42 }
43 #[allow(dead_code)]
44 pub fn dependencies_of(&self, node: u32) -> Vec<u32> {
45 self.edges
46 .iter()
47 .filter(|(_, dep)| *dep == node)
48 .map(|(d, _)| *d)
49 .collect()
50 }
51 #[allow(dead_code)]
52 pub fn topological_sort(&self) -> Vec<u32> {
53 let mut in_degree: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
54 for &n in &self.nodes {
55 in_degree.insert(n, 0);
56 }
57 for (_, dep) in &self.edges {
58 *in_degree.entry(*dep).or_insert(0) += 1;
59 }
60 let mut queue: std::collections::VecDeque<u32> = self
61 .nodes
62 .iter()
63 .filter(|&&n| in_degree[&n] == 0)
64 .copied()
65 .collect();
66 let mut result = Vec::new();
67 while let Some(node) = queue.pop_front() {
68 result.push(node);
69 for dep in self.dependents_of(node) {
70 let cnt = in_degree.entry(dep).or_insert(0);
71 *cnt = cnt.saturating_sub(1);
72 if *cnt == 0 {
73 queue.push_back(dep);
74 }
75 }
76 }
77 result
78 }
79 #[allow(dead_code)]
80 pub fn has_cycle(&self) -> bool {
81 self.topological_sort().len() < self.nodes.len()
82 }
83}
84#[allow(dead_code)]
85pub struct ChplConstantFoldingHelper;
86impl ChplConstantFoldingHelper {
87 #[allow(dead_code)]
88 pub fn fold_add_i64(a: i64, b: i64) -> Option<i64> {
89 a.checked_add(b)
90 }
91 #[allow(dead_code)]
92 pub fn fold_sub_i64(a: i64, b: i64) -> Option<i64> {
93 a.checked_sub(b)
94 }
95 #[allow(dead_code)]
96 pub fn fold_mul_i64(a: i64, b: i64) -> Option<i64> {
97 a.checked_mul(b)
98 }
99 #[allow(dead_code)]
100 pub fn fold_div_i64(a: i64, b: i64) -> Option<i64> {
101 if b == 0 {
102 None
103 } else {
104 a.checked_div(b)
105 }
106 }
107 #[allow(dead_code)]
108 pub fn fold_add_f64(a: f64, b: f64) -> f64 {
109 a + b
110 }
111 #[allow(dead_code)]
112 pub fn fold_mul_f64(a: f64, b: f64) -> f64 {
113 a * b
114 }
115 #[allow(dead_code)]
116 pub fn fold_neg_i64(a: i64) -> Option<i64> {
117 a.checked_neg()
118 }
119 #[allow(dead_code)]
120 pub fn fold_not_bool(a: bool) -> bool {
121 !a
122 }
123 #[allow(dead_code)]
124 pub fn fold_and_bool(a: bool, b: bool) -> bool {
125 a && b
126 }
127 #[allow(dead_code)]
128 pub fn fold_or_bool(a: bool, b: bool) -> bool {
129 a || b
130 }
131 #[allow(dead_code)]
132 pub fn fold_shl_i64(a: i64, b: u32) -> Option<i64> {
133 a.checked_shl(b)
134 }
135 #[allow(dead_code)]
136 pub fn fold_shr_i64(a: i64, b: u32) -> Option<i64> {
137 a.checked_shr(b)
138 }
139 #[allow(dead_code)]
140 pub fn fold_rem_i64(a: i64, b: i64) -> Option<i64> {
141 if b == 0 {
142 None
143 } else {
144 Some(a % b)
145 }
146 }
147 #[allow(dead_code)]
148 pub fn fold_bitand_i64(a: i64, b: i64) -> i64 {
149 a & b
150 }
151 #[allow(dead_code)]
152 pub fn fold_bitor_i64(a: i64, b: i64) -> i64 {
153 a | b
154 }
155 #[allow(dead_code)]
156 pub fn fold_bitxor_i64(a: i64, b: i64) -> i64 {
157 a ^ b
158 }
159 #[allow(dead_code)]
160 pub fn fold_bitnot_i64(a: i64) -> i64 {
161 !a
162 }
163}
164pub struct ChapelBackend {
166 pub(super) buf: String,
168 pub(super) indent: usize,
170 pub(super) indent_str: String,
172 pub(super) config: ChapelConfig,
174 pub(super) _intern: HashMap<String, u32>,
176}
177impl ChapelBackend {
178 pub fn new() -> Self {
180 ChapelBackend::with_config(ChapelConfig::default())
181 }
182 pub fn with_config(config: ChapelConfig) -> Self {
184 let indent_str = " ".repeat(config.indent_width);
185 ChapelBackend {
186 buf: String::new(),
187 indent: 0,
188 indent_str,
189 config,
190 _intern: HashMap::new(),
191 }
192 }
193 pub(super) fn push(&mut self, s: &str) {
194 self.buf.push_str(s);
195 }
196 pub(super) fn push_char(&mut self, c: char) {
197 self.buf.push(c);
198 }
199 pub(super) fn newline(&mut self) {
200 self.buf.push('\n');
201 }
202 pub(super) fn emit_indent(&mut self) {
203 for _ in 0..self.indent {
204 self.buf.push_str(&self.indent_str.clone());
205 }
206 }
207 pub(super) fn emit_line(&mut self, s: &str) {
208 self.emit_indent();
209 self.push(s);
210 self.newline();
211 }
212 pub(super) fn indent_in(&mut self) {
213 self.indent += 1;
214 }
215 pub(super) fn indent_out(&mut self) {
216 if self.indent > 0 {
217 self.indent -= 1;
218 }
219 }
220 pub fn emit_expr(&mut self, expr: &ChapelExpr) {
222 match expr {
223 ChapelExpr::IntLit(n) => self.push(&n.to_string()),
224 ChapelExpr::RealLit(v) => self.push(&format!("{v}")),
225 ChapelExpr::BoolLit(b) => self.push(if *b { "true" } else { "false" }),
226 ChapelExpr::StrLit(s) => {
227 self.push_char('"');
228 self.push(s);
229 self.push_char('"');
230 }
231 ChapelExpr::Var(name) => self.push(name),
232 ChapelExpr::Apply(f, args) => {
233 self.emit_expr(f);
234 self.push("(");
235 for (i, arg) in args.iter().enumerate() {
236 if i > 0 {
237 self.push(", ");
238 }
239 self.emit_expr(arg);
240 }
241 self.push(")");
242 }
243 ChapelExpr::Index(arr, idx) => {
244 self.emit_expr(arr);
245 self.push("[");
246 self.emit_expr(idx);
247 self.push("]");
248 }
249 ChapelExpr::FieldAccess(obj, field) => {
250 self.emit_expr_paren(obj);
251 self.push(".");
252 self.push(field);
253 }
254 ChapelExpr::BinOp(op, lhs, rhs) => {
255 self.emit_expr_paren(lhs);
256 self.push(" ");
257 self.push(op);
258 self.push(" ");
259 self.emit_expr_paren(rhs);
260 }
261 ChapelExpr::UnOp(op, e) => {
262 self.push(op);
263 self.emit_expr_paren(e);
264 }
265 ChapelExpr::RangeLit(lo, hi, count_based) => {
266 self.emit_expr(lo);
267 if *count_based {
268 self.push("..#");
269 } else {
270 self.push("..");
271 }
272 self.emit_expr(hi);
273 }
274 ChapelExpr::ReduceExpr(op, arr) => {
275 self.push(op);
276 self.push(" reduce ");
277 self.emit_expr_paren(arr);
278 }
279 ChapelExpr::ForallExpr(idx, domain, body) => {
280 self.push("[");
281 self.push(idx);
282 self.push(" in ");
283 self.emit_expr(domain);
284 self.push("] ");
285 self.emit_expr(body);
286 }
287 ChapelExpr::CoforallExpr(idx, domain, body) => {
288 self.push("coforall ");
289 self.push(idx);
290 self.push(" in ");
291 self.emit_expr(domain);
292 self.push(" { ");
293 self.emit_expr(body);
294 self.push(" }");
295 }
296 ChapelExpr::TupleLit(elems) => {
297 self.push("(");
298 for (i, e) in elems.iter().enumerate() {
299 if i > 0 {
300 self.push(", ");
301 }
302 self.emit_expr(e);
303 }
304 self.push(")");
305 }
306 ChapelExpr::ArrayLit(elems) => {
307 self.push("[");
308 for (i, e) in elems.iter().enumerate() {
309 if i > 0 {
310 self.push(", ");
311 }
312 self.emit_expr(e);
313 }
314 self.push("]");
315 }
316 ChapelExpr::Cast(e, ty) => {
317 self.emit_expr_paren(e);
318 self.push(": ");
319 self.push(&ty.to_string());
320 }
321 ChapelExpr::IfExpr(cond, t, e) => {
322 self.push("if ");
323 self.emit_expr(cond);
324 self.push(" then ");
325 self.emit_expr(t);
326 self.push(" else ");
327 self.emit_expr(e);
328 }
329 ChapelExpr::New(ty, args) => {
330 self.push("new ");
331 self.push(&ty.to_string());
332 self.push("(");
333 for (i, arg) in args.iter().enumerate() {
334 if i > 0 {
335 self.push(", ");
336 }
337 self.emit_expr(arg);
338 }
339 self.push(")");
340 }
341 ChapelExpr::Nil => self.push("nil"),
342 ChapelExpr::Here => self.push("here"),
343 ChapelExpr::NumLocales => self.push("numLocales"),
344 ChapelExpr::This => self.push("this"),
345 ChapelExpr::TypeOf(e) => {
346 self.emit_expr(e);
347 self.push(".type");
348 }
349 ChapelExpr::DomainLit(dims) => {
350 self.push("{");
351 for (i, d) in dims.iter().enumerate() {
352 if i > 0 {
353 self.push(", ");
354 }
355 self.emit_expr(d);
356 }
357 self.push("}");
358 }
359 }
360 }
361 pub(super) fn emit_expr_paren(&mut self, expr: &ChapelExpr) {
363 let needs_paren = matches!(
364 expr,
365 ChapelExpr::BinOp(..)
366 | ChapelExpr::IfExpr(..)
367 | ChapelExpr::ForallExpr(..)
368 | ChapelExpr::CoforallExpr(..)
369 | ChapelExpr::Cast(..)
370 );
371 if needs_paren {
372 self.push("(");
373 self.emit_expr(expr);
374 self.push(")");
375 } else {
376 self.emit_expr(expr);
377 }
378 }
379 pub(super) fn emit_param(&mut self, param: &ChapelParam) {
380 if let Some(intent) = ¶m.intent {
381 self.push(&intent.to_string());
382 self.push(" ");
383 }
384 self.push(¶m.name);
385 if let Some(ty) = ¶m.ty {
386 self.push(": ");
387 self.push(&ty.to_string());
388 }
389 if let Some(def) = ¶m.default {
390 self.push(" = ");
391 let def = def.clone();
392 self.emit_expr(&def);
393 }
394 }
395 pub fn emit_stmt(&mut self, stmt: &ChapelStmt) {
397 match stmt {
398 ChapelStmt::VarDecl(name, ty, init) => {
399 self.emit_indent();
400 self.push("var ");
401 self.push(name);
402 if let Some(t) = ty {
403 if self.config.annotate_vars {
404 self.push(": ");
405 self.push(&t.to_string());
406 }
407 }
408 if let Some(e) = init {
409 self.push(" = ");
410 let e = e.clone();
411 self.emit_expr(&e);
412 }
413 self.push(";");
414 self.newline();
415 }
416 ChapelStmt::ConstDecl(name, ty, expr) => {
417 self.emit_indent();
418 self.push("const ");
419 self.push(name);
420 if let Some(t) = ty {
421 if self.config.annotate_vars {
422 self.push(": ");
423 self.push(&t.to_string());
424 }
425 }
426 self.push(" = ");
427 let expr = expr.clone();
428 self.emit_expr(&expr);
429 self.push(";");
430 self.newline();
431 }
432 ChapelStmt::Assign(lhs, rhs) => {
433 self.emit_indent();
434 let lhs = lhs.clone();
435 let rhs = rhs.clone();
436 self.emit_expr(&lhs);
437 self.push(" = ");
438 self.emit_expr(&rhs);
439 self.push(";");
440 self.newline();
441 }
442 ChapelStmt::CompoundAssign(op, lhs, rhs) => {
443 self.emit_indent();
444 let lhs = lhs.clone();
445 let rhs = rhs.clone();
446 self.emit_expr(&lhs);
447 self.push(" ");
448 self.push(op);
449 self.push("= ");
450 self.emit_expr(&rhs);
451 self.push(";");
452 self.newline();
453 }
454 ChapelStmt::IfElse(cond, then_body, else_body) => {
455 self.emit_indent();
456 self.push("if ");
457 let cond = cond.clone();
458 self.emit_expr(&cond);
459 self.push(" {");
460 self.newline();
461 self.indent_in();
462 let then_body = then_body.clone();
463 for s in &then_body {
464 self.emit_stmt(s);
465 }
466 self.indent_out();
467 if let Some(eb) = else_body {
468 self.emit_indent();
469 self.push("} else {");
470 self.newline();
471 self.indent_in();
472 let eb = eb.clone();
473 for s in &eb {
474 self.emit_stmt(s);
475 }
476 self.indent_out();
477 }
478 self.emit_line("}");
479 }
480 ChapelStmt::ForLoop(idx, domain, body) => {
481 self.emit_indent();
482 self.push("for ");
483 self.push(idx);
484 self.push(" in ");
485 let domain = domain.clone();
486 self.emit_expr(&domain);
487 self.push(" {");
488 self.newline();
489 self.indent_in();
490 let body = body.clone();
491 for s in &body {
492 self.emit_stmt(s);
493 }
494 self.indent_out();
495 self.emit_line("}");
496 }
497 ChapelStmt::ForallLoop(idx, domain, body) => {
498 self.emit_indent();
499 self.push("forall ");
500 self.push(idx);
501 self.push(" in ");
502 let domain = domain.clone();
503 self.emit_expr(&domain);
504 self.push(" {");
505 self.newline();
506 self.indent_in();
507 let body = body.clone();
508 for s in &body {
509 self.emit_stmt(s);
510 }
511 self.indent_out();
512 self.emit_line("}");
513 }
514 ChapelStmt::ForallReduce(idx, domain, op, acc, body) => {
515 self.emit_indent();
516 self.push("forall ");
517 self.push(idx);
518 self.push(" in ");
519 let domain = domain.clone();
520 self.emit_expr(&domain);
521 self.push(" with (");
522 self.push(op);
523 self.push(" reduce ");
524 self.push(acc);
525 self.push(") {");
526 self.newline();
527 self.indent_in();
528 let body = body.clone();
529 for s in &body {
530 self.emit_stmt(s);
531 }
532 self.indent_out();
533 self.emit_line("}");
534 }
535 ChapelStmt::CoforallLoop(idx, domain, body) => {
536 self.emit_indent();
537 self.push("coforall ");
538 self.push(idx);
539 self.push(" in ");
540 let domain = domain.clone();
541 self.emit_expr(&domain);
542 self.push(" {");
543 self.newline();
544 self.indent_in();
545 let body = body.clone();
546 for s in &body {
547 self.emit_stmt(s);
548 }
549 self.indent_out();
550 self.emit_line("}");
551 }
552 ChapelStmt::WhileLoop(cond, body) => {
553 self.emit_indent();
554 self.push("while ");
555 let cond = cond.clone();
556 self.emit_expr(&cond);
557 self.push(" {");
558 self.newline();
559 self.indent_in();
560 let body = body.clone();
561 for s in &body {
562 self.emit_stmt(s);
563 }
564 self.indent_out();
565 self.emit_line("}");
566 }
567 ChapelStmt::DoWhileLoop(body, cond) => {
568 self.emit_line("do {");
569 self.indent_in();
570 let body = body.clone();
571 for s in &body {
572 self.emit_stmt(s);
573 }
574 self.indent_out();
575 self.emit_indent();
576 self.push("} while ");
577 let cond = cond.clone();
578 self.emit_expr(&cond);
579 self.push(";");
580 self.newline();
581 }
582 ChapelStmt::ReturnStmt(e) => {
583 self.emit_indent();
584 self.push("return");
585 if let Some(expr) = e {
586 self.push(" ");
587 let expr = expr.clone();
588 self.emit_expr(&expr);
589 }
590 self.push(";");
591 self.newline();
592 }
593 ChapelStmt::ProcDef(proc) => {
594 self.emit_proc(proc);
595 }
596 ChapelStmt::RecordDef(rec) => {
597 self.emit_record(rec);
598 }
599 ChapelStmt::ClassDef(cls) => {
600 self.emit_class(cls);
601 }
602 ChapelStmt::ExprStmt(e) => {
603 self.emit_indent();
604 let e = e.clone();
605 self.emit_expr(&e);
606 self.push(";");
607 self.newline();
608 }
609 ChapelStmt::Writeln(args) => {
610 self.emit_indent();
611 self.push("writeln(");
612 let args = args.clone();
613 for (i, arg) in args.iter().enumerate() {
614 if i > 0 {
615 self.push(", ");
616 }
617 self.emit_expr(arg);
618 }
619 self.push(");");
620 self.newline();
621 }
622 ChapelStmt::Write(args) => {
623 self.emit_indent();
624 self.push("write(");
625 let args = args.clone();
626 for (i, arg) in args.iter().enumerate() {
627 if i > 0 {
628 self.push(", ");
629 }
630 self.emit_expr(arg);
631 }
632 self.push(");");
633 self.newline();
634 }
635 ChapelStmt::Break => {
636 self.emit_line("break;");
637 }
638 ChapelStmt::Continue => {
639 self.emit_line("continue;");
640 }
641 ChapelStmt::Halt(msg) => {
642 self.emit_indent();
643 self.push("halt(\"");
644 self.push(msg);
645 self.push("\");");
646 self.newline();
647 }
648 ChapelStmt::On(locale, body) => {
649 self.emit_indent();
650 self.push("on ");
651 let locale = locale.clone();
652 self.emit_expr(&locale);
653 self.push(" {");
654 self.newline();
655 self.indent_in();
656 let body = body.clone();
657 for s in &body {
658 self.emit_stmt(s);
659 }
660 self.indent_out();
661 self.emit_line("}");
662 }
663 ChapelStmt::Begin(body) => {
664 self.emit_line("begin {");
665 self.indent_in();
666 let body = body.clone();
667 for s in &body {
668 self.emit_stmt(s);
669 }
670 self.indent_out();
671 self.emit_line("}");
672 }
673 ChapelStmt::SyncBlock(body) => {
674 self.emit_line("sync {");
675 self.indent_in();
676 let body = body.clone();
677 for s in &body {
678 self.emit_stmt(s);
679 }
680 self.indent_out();
681 self.emit_line("}");
682 }
683 ChapelStmt::Comment(text) => {
684 self.emit_indent();
685 self.push("// ");
686 self.push(text);
687 self.newline();
688 }
689 ChapelStmt::Blank => {
690 self.newline();
691 }
692 }
693 }
694 pub fn emit_proc(&mut self, proc: &ChapelProc) {
696 self.emit_indent();
697 if proc.is_inline {
698 self.push("inline ");
699 }
700 if proc.is_override {
701 self.push("override ");
702 }
703 if proc.is_iter {
704 self.push("iter ");
705 } else if proc.is_operator {
706 self.push("operator ");
707 } else {
708 self.push("proc ");
709 }
710 self.push(&proc.name);
711 self.push("(");
712 let params = proc.params.clone();
713 for (i, param) in params.iter().enumerate() {
714 if i > 0 {
715 self.push(", ");
716 }
717 self.emit_param(param);
718 }
719 self.push(")");
720 if let Some(ret) = &proc.return_type {
721 self.push(": ");
722 self.push(&ret.to_string());
723 }
724 if let Some(wh) = &proc.where_clause {
725 self.push(" where ");
726 self.push(wh);
727 }
728 self.push(" {");
729 self.newline();
730 self.indent_in();
731 let body = proc.body.clone();
732 for stmt in &body {
733 self.emit_stmt(stmt);
734 }
735 self.indent_out();
736 self.emit_line("}");
737 self.newline();
738 }
739 pub fn emit_record(&mut self, rec: &ChapelRecord) {
741 self.emit_indent();
742 self.push("record ");
743 self.push(&rec.name);
744 if !rec.type_params.is_empty() {
745 self.push("(");
746 for (i, tp) in rec.type_params.iter().enumerate() {
747 if i > 0 {
748 self.push(", ");
749 }
750 self.push("type ");
751 self.push(tp);
752 }
753 self.push(")");
754 }
755 self.push(" {");
756 self.newline();
757 self.indent_in();
758 let fields = rec.fields.clone();
759 for field in &fields {
760 self.emit_indent();
761 if field.is_const {
762 self.push("const ");
763 } else {
764 self.push("var ");
765 }
766 self.push(&field.name);
767 self.push(": ");
768 self.push(&field.ty.to_string());
769 if let Some(def) = &field.default {
770 self.push(" = ");
771 let def = def.clone();
772 self.emit_expr(&def);
773 }
774 self.push(";");
775 self.newline();
776 }
777 let methods = rec.methods.clone();
778 for method in &methods {
779 self.emit_proc(method);
780 }
781 self.indent_out();
782 self.emit_line("}");
783 self.newline();
784 }
785 pub fn emit_class(&mut self, cls: &ChapelClass) {
787 self.emit_indent();
788 self.push("class ");
789 self.push(&cls.name);
790 if !cls.type_params.is_empty() {
791 self.push("(");
792 for (i, tp) in cls.type_params.iter().enumerate() {
793 if i > 0 {
794 self.push(", ");
795 }
796 self.push("type ");
797 self.push(tp);
798 }
799 self.push(")");
800 }
801 if let Some(parent) = &cls.parent {
802 self.push(" : ");
803 self.push(parent);
804 }
805 self.push(" {");
806 self.newline();
807 self.indent_in();
808 let fields = cls.fields.clone();
809 for field in &fields {
810 self.emit_indent();
811 if field.is_const {
812 self.push("const ");
813 } else {
814 self.push("var ");
815 }
816 self.push(&field.name);
817 self.push(": ");
818 self.push(&field.ty.to_string());
819 if let Some(def) = &field.default {
820 self.push(" = ");
821 let def = def.clone();
822 self.emit_expr(&def);
823 }
824 self.push(";");
825 self.newline();
826 }
827 let methods = cls.methods.clone();
828 for method in &methods {
829 self.emit_proc(method);
830 }
831 self.indent_out();
832 self.emit_line("}");
833 self.newline();
834 }
835 pub fn emit_module(&mut self, module: &ChapelModule) {
837 if let Some(doc) = &module.doc.clone() {
838 for line in doc.lines() {
839 self.push("// ");
840 self.push(line);
841 self.newline();
842 }
843 self.newline();
844 }
845 let has_name = module.name.is_some();
846 if let Some(name) = &module.name.clone() {
847 self.emit_line(&format!("module {name} {{"));
848 self.indent_in();
849 }
850 for u in &module.uses.clone() {
851 self.emit_line(&format!("use {u};"));
852 }
853 if !module.uses.is_empty() {
854 self.newline();
855 }
856 for r in &module.requires.clone() {
857 self.emit_line(&format!("require \"{r}\";"));
858 }
859 if !module.requires.is_empty() {
860 self.newline();
861 }
862 for (name, ty, def) in &module.configs.clone() {
863 self.emit_indent();
864 self.push("config var ");
865 self.push(name);
866 self.push(": ");
867 self.push(&ty.to_string());
868 if let Some(d) = def {
869 self.push(" = ");
870 let d = d.clone();
871 self.emit_expr(&d);
872 }
873 self.push(";");
874 self.newline();
875 }
876 if !module.configs.is_empty() {
877 self.newline();
878 }
879 for (name, ty, expr) in &module.globals.clone() {
880 self.emit_indent();
881 self.push("const ");
882 self.push(name);
883 self.push(": ");
884 self.push(&ty.to_string());
885 self.push(" = ");
886 let expr = expr.clone();
887 self.emit_expr(&expr);
888 self.push(";");
889 self.newline();
890 }
891 if !module.globals.is_empty() {
892 self.newline();
893 }
894 for rec in &module.records.clone() {
895 self.emit_record(rec);
896 }
897 for cls in &module.classes.clone() {
898 self.emit_class(cls);
899 }
900 for proc in &module.procs.clone() {
901 self.emit_proc(proc);
902 }
903 for sub in &module.submodules.clone() {
904 self.emit_module(sub);
905 }
906 if has_name {
907 self.indent_out();
908 self.emit_line("}");
909 }
910 }
911 pub fn finish(&mut self) -> String {
913 std::mem::take(&mut self.buf)
914 }
915 pub fn generate(module: &ChapelModule) -> String {
917 let mut backend = ChapelBackend::new();
918 backend.emit_module(module);
919 backend.finish()
920 }
921 pub fn generate_with_config(module: &ChapelModule, config: ChapelConfig) -> String {
923 let mut backend = ChapelBackend::with_config(config);
924 backend.emit_module(module);
925 backend.finish()
926 }
927}
928#[derive(Debug, Clone, PartialEq)]
930pub enum ChapelIntent {
931 In,
932 Out,
933 InOut,
934 Ref,
935 Const,
936 ConstRef,
937 Param,
938 Type,
939}
940#[allow(dead_code)]
941pub struct ChplPassRegistry {
942 pub(super) configs: Vec<ChplPassConfig>,
943 pub(super) stats: std::collections::HashMap<String, ChplPassStats>,
944}
945impl ChplPassRegistry {
946 #[allow(dead_code)]
947 pub fn new() -> Self {
948 ChplPassRegistry {
949 configs: Vec::new(),
950 stats: std::collections::HashMap::new(),
951 }
952 }
953 #[allow(dead_code)]
954 pub fn register(&mut self, config: ChplPassConfig) {
955 self.stats
956 .insert(config.pass_name.clone(), ChplPassStats::new());
957 self.configs.push(config);
958 }
959 #[allow(dead_code)]
960 pub fn enabled_passes(&self) -> Vec<&ChplPassConfig> {
961 self.configs.iter().filter(|c| c.enabled).collect()
962 }
963 #[allow(dead_code)]
964 pub fn get_stats(&self, name: &str) -> Option<&ChplPassStats> {
965 self.stats.get(name)
966 }
967 #[allow(dead_code)]
968 pub fn total_passes(&self) -> usize {
969 self.configs.len()
970 }
971 #[allow(dead_code)]
972 pub fn enabled_count(&self) -> usize {
973 self.enabled_passes().len()
974 }
975 #[allow(dead_code)]
976 pub fn update_stats(&mut self, name: &str, changes: u64, time_ms: u64, iter: u32) {
977 if let Some(stats) = self.stats.get_mut(name) {
978 stats.record_run(changes, time_ms, iter);
979 }
980 }
981}
982#[allow(dead_code)]
984#[derive(Debug, Clone, Default)]
985pub struct ChapelExtConstFolder {
986 pub(super) folds: usize,
987 pub(super) failures: usize,
988 pub(super) enabled: bool,
989}
990impl ChapelExtConstFolder {
991 #[allow(dead_code)]
992 pub fn new() -> Self {
993 Self {
994 folds: 0,
995 failures: 0,
996 enabled: true,
997 }
998 }
999 #[allow(dead_code)]
1000 pub fn add_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1001 self.folds += 1;
1002 a.checked_add(b)
1003 }
1004 #[allow(dead_code)]
1005 pub fn sub_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1006 self.folds += 1;
1007 a.checked_sub(b)
1008 }
1009 #[allow(dead_code)]
1010 pub fn mul_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1011 self.folds += 1;
1012 a.checked_mul(b)
1013 }
1014 #[allow(dead_code)]
1015 pub fn div_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1016 if b == 0 {
1017 self.failures += 1;
1018 None
1019 } else {
1020 self.folds += 1;
1021 a.checked_div(b)
1022 }
1023 }
1024 #[allow(dead_code)]
1025 pub fn rem_i64(&mut self, a: i64, b: i64) -> Option<i64> {
1026 if b == 0 {
1027 self.failures += 1;
1028 None
1029 } else {
1030 self.folds += 1;
1031 a.checked_rem(b)
1032 }
1033 }
1034 #[allow(dead_code)]
1035 pub fn neg_i64(&mut self, a: i64) -> Option<i64> {
1036 self.folds += 1;
1037 a.checked_neg()
1038 }
1039 #[allow(dead_code)]
1040 pub fn shl_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1041 if s >= 64 {
1042 self.failures += 1;
1043 None
1044 } else {
1045 self.folds += 1;
1046 a.checked_shl(s)
1047 }
1048 }
1049 #[allow(dead_code)]
1050 pub fn shr_i64(&mut self, a: i64, s: u32) -> Option<i64> {
1051 if s >= 64 {
1052 self.failures += 1;
1053 None
1054 } else {
1055 self.folds += 1;
1056 a.checked_shr(s)
1057 }
1058 }
1059 #[allow(dead_code)]
1060 pub fn and_i64(&mut self, a: i64, b: i64) -> i64 {
1061 self.folds += 1;
1062 a & b
1063 }
1064 #[allow(dead_code)]
1065 pub fn or_i64(&mut self, a: i64, b: i64) -> i64 {
1066 self.folds += 1;
1067 a | b
1068 }
1069 #[allow(dead_code)]
1070 pub fn xor_i64(&mut self, a: i64, b: i64) -> i64 {
1071 self.folds += 1;
1072 a ^ b
1073 }
1074 #[allow(dead_code)]
1075 pub fn not_i64(&mut self, a: i64) -> i64 {
1076 self.folds += 1;
1077 !a
1078 }
1079 #[allow(dead_code)]
1080 pub fn fold_count(&self) -> usize {
1081 self.folds
1082 }
1083 #[allow(dead_code)]
1084 pub fn failure_count(&self) -> usize {
1085 self.failures
1086 }
1087 #[allow(dead_code)]
1088 pub fn enable(&mut self) {
1089 self.enabled = true;
1090 }
1091 #[allow(dead_code)]
1092 pub fn disable(&mut self) {
1093 self.enabled = false;
1094 }
1095 #[allow(dead_code)]
1096 pub fn is_enabled(&self) -> bool {
1097 self.enabled
1098 }
1099}
1100#[allow(dead_code)]
1101#[derive(Debug, Clone)]
1102pub struct ChplPassConfig {
1103 pub phase: ChplPassPhase,
1104 pub enabled: bool,
1105 pub max_iterations: u32,
1106 pub debug_output: bool,
1107 pub pass_name: String,
1108}
1109impl ChplPassConfig {
1110 #[allow(dead_code)]
1111 pub fn new(name: impl Into<String>, phase: ChplPassPhase) -> Self {
1112 ChplPassConfig {
1113 phase,
1114 enabled: true,
1115 max_iterations: 10,
1116 debug_output: false,
1117 pass_name: name.into(),
1118 }
1119 }
1120 #[allow(dead_code)]
1121 pub fn disabled(mut self) -> Self {
1122 self.enabled = false;
1123 self
1124 }
1125 #[allow(dead_code)]
1126 pub fn with_debug(mut self) -> Self {
1127 self.debug_output = true;
1128 self
1129 }
1130 #[allow(dead_code)]
1131 pub fn max_iter(mut self, n: u32) -> Self {
1132 self.max_iterations = n;
1133 self
1134 }
1135}
1136#[derive(Debug, Clone, PartialEq)]
1138pub enum ChapelType {
1139 Int(Option<u32>),
1141 UInt(Option<u32>),
1143 Real(Option<u32>),
1145 Imag(Option<u32>),
1147 Complex(Option<u32>),
1149 Bool,
1151 String,
1153 Bytes,
1155 Range(Box<ChapelType>),
1157 Domain(u32, Box<ChapelType>),
1159 Array(Box<ChapelType>, Box<ChapelType>),
1161 Record(String),
1163 Class(String),
1165 Union(String),
1167 EnumType(String),
1169 ProcType(Vec<ChapelType>, Box<ChapelType>),
1171 Tuple(Vec<ChapelType>),
1173 Named(String),
1175 Void,
1177 TypeVar(String),
1179 Atomic(Box<ChapelType>),
1181 Sync(Box<ChapelType>),
1183 Single(Box<ChapelType>),
1185 Owned(Box<ChapelType>),
1187 Shared(Box<ChapelType>),
1189 Unmanaged(Box<ChapelType>),
1191}
1192#[allow(dead_code)]
1194#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1195pub enum ChapelExtPassPhase {
1196 Early,
1197 Middle,
1198 Late,
1199 Finalize,
1200}
1201impl ChapelExtPassPhase {
1202 #[allow(dead_code)]
1203 pub fn is_early(&self) -> bool {
1204 matches!(self, Self::Early)
1205 }
1206 #[allow(dead_code)]
1207 pub fn is_middle(&self) -> bool {
1208 matches!(self, Self::Middle)
1209 }
1210 #[allow(dead_code)]
1211 pub fn is_late(&self) -> bool {
1212 matches!(self, Self::Late)
1213 }
1214 #[allow(dead_code)]
1215 pub fn is_finalize(&self) -> bool {
1216 matches!(self, Self::Finalize)
1217 }
1218 #[allow(dead_code)]
1219 pub fn order(&self) -> u32 {
1220 match self {
1221 Self::Early => 0,
1222 Self::Middle => 1,
1223 Self::Late => 2,
1224 Self::Finalize => 3,
1225 }
1226 }
1227 #[allow(dead_code)]
1228 pub fn from_order(n: u32) -> Option<Self> {
1229 match n {
1230 0 => Some(Self::Early),
1231 1 => Some(Self::Middle),
1232 2 => Some(Self::Late),
1233 3 => Some(Self::Finalize),
1234 _ => None,
1235 }
1236 }
1237}
1238#[derive(Debug, Clone)]
1240pub struct ChapelConfig {
1241 pub indent_width: usize,
1243 pub annotate_vars: bool,
1245 pub use_writeln: bool,
1247}
1248#[derive(Debug, Clone)]
1250pub enum ChapelExpr {
1251 IntLit(i64),
1253 RealLit(f64),
1255 BoolLit(bool),
1257 StrLit(String),
1259 Var(String),
1261 Apply(Box<ChapelExpr>, Vec<ChapelExpr>),
1263 Index(Box<ChapelExpr>, Box<ChapelExpr>),
1265 FieldAccess(Box<ChapelExpr>, String),
1267 BinOp(String, Box<ChapelExpr>, Box<ChapelExpr>),
1269 UnOp(String, Box<ChapelExpr>),
1271 RangeLit(Box<ChapelExpr>, Box<ChapelExpr>, bool),
1273 ReduceExpr(String, Box<ChapelExpr>),
1275 ForallExpr(String, Box<ChapelExpr>, Box<ChapelExpr>),
1277 CoforallExpr(String, Box<ChapelExpr>, Box<ChapelExpr>),
1279 TupleLit(Vec<ChapelExpr>),
1281 ArrayLit(Vec<ChapelExpr>),
1283 Cast(Box<ChapelExpr>, ChapelType),
1285 IfExpr(Box<ChapelExpr>, Box<ChapelExpr>, Box<ChapelExpr>),
1287 New(ChapelType, Vec<ChapelExpr>),
1289 Nil,
1291 Here,
1293 NumLocales,
1295 This,
1297 TypeOf(Box<ChapelExpr>),
1299 DomainLit(Vec<ChapelExpr>),
1301}
1302#[allow(dead_code)]
1303#[derive(Debug, Clone)]
1304pub struct ChplAnalysisCache {
1305 pub(super) entries: std::collections::HashMap<String, ChplCacheEntry>,
1306 pub(super) max_size: usize,
1307 pub(super) hits: u64,
1308 pub(super) misses: u64,
1309}
1310impl ChplAnalysisCache {
1311 #[allow(dead_code)]
1312 pub fn new(max_size: usize) -> Self {
1313 ChplAnalysisCache {
1314 entries: std::collections::HashMap::new(),
1315 max_size,
1316 hits: 0,
1317 misses: 0,
1318 }
1319 }
1320 #[allow(dead_code)]
1321 pub fn get(&mut self, key: &str) -> Option<&ChplCacheEntry> {
1322 if self.entries.contains_key(key) {
1323 self.hits += 1;
1324 self.entries.get(key)
1325 } else {
1326 self.misses += 1;
1327 None
1328 }
1329 }
1330 #[allow(dead_code)]
1331 pub fn insert(&mut self, key: String, data: Vec<u8>) {
1332 if self.entries.len() >= self.max_size {
1333 if let Some(oldest) = self.entries.keys().next().cloned() {
1334 self.entries.remove(&oldest);
1335 }
1336 }
1337 self.entries.insert(
1338 key.clone(),
1339 ChplCacheEntry {
1340 key,
1341 data,
1342 timestamp: 0,
1343 valid: true,
1344 },
1345 );
1346 }
1347 #[allow(dead_code)]
1348 pub fn invalidate(&mut self, key: &str) {
1349 if let Some(entry) = self.entries.get_mut(key) {
1350 entry.valid = false;
1351 }
1352 }
1353 #[allow(dead_code)]
1354 pub fn clear(&mut self) {
1355 self.entries.clear();
1356 }
1357 #[allow(dead_code)]
1358 pub fn hit_rate(&self) -> f64 {
1359 let total = self.hits + self.misses;
1360 if total == 0 {
1361 return 0.0;
1362 }
1363 self.hits as f64 / total as f64
1364 }
1365 #[allow(dead_code)]
1366 pub fn size(&self) -> usize {
1367 self.entries.len()
1368 }
1369}
1370#[derive(Debug, Clone)]
1372pub enum ChapelStmt {
1373 VarDecl(String, Option<ChapelType>, Option<ChapelExpr>),
1375 ConstDecl(String, Option<ChapelType>, ChapelExpr),
1377 Assign(ChapelExpr, ChapelExpr),
1379 CompoundAssign(String, ChapelExpr, ChapelExpr),
1381 IfElse(ChapelExpr, Vec<ChapelStmt>, Option<Vec<ChapelStmt>>),
1383 ForLoop(String, ChapelExpr, Vec<ChapelStmt>),
1385 ForallLoop(String, ChapelExpr, Vec<ChapelStmt>),
1387 ForallReduce(String, ChapelExpr, String, String, Vec<ChapelStmt>),
1389 CoforallLoop(String, ChapelExpr, Vec<ChapelStmt>),
1391 WhileLoop(ChapelExpr, Vec<ChapelStmt>),
1393 DoWhileLoop(Vec<ChapelStmt>, ChapelExpr),
1395 ReturnStmt(Option<ChapelExpr>),
1397 ProcDef(ChapelProc),
1399 RecordDef(ChapelRecord),
1401 ClassDef(ChapelClass),
1403 ExprStmt(ChapelExpr),
1405 Writeln(Vec<ChapelExpr>),
1407 Write(Vec<ChapelExpr>),
1409 Break,
1411 Continue,
1413 Halt(String),
1415 On(ChapelExpr, Vec<ChapelStmt>),
1417 Begin(Vec<ChapelStmt>),
1419 SyncBlock(Vec<ChapelStmt>),
1421 Comment(String),
1423 Blank,
1425}
1426#[allow(dead_code)]
1428#[derive(Debug)]
1429pub struct ChapelExtCache {
1430 pub(super) entries: Vec<(u64, Vec<u8>, bool, u32)>,
1431 pub(super) cap: usize,
1432 pub(super) total_hits: u64,
1433 pub(super) total_misses: u64,
1434}
1435impl ChapelExtCache {
1436 #[allow(dead_code)]
1437 pub fn new(cap: usize) -> Self {
1438 Self {
1439 entries: Vec::new(),
1440 cap,
1441 total_hits: 0,
1442 total_misses: 0,
1443 }
1444 }
1445 #[allow(dead_code)]
1446 pub fn get(&mut self, key: u64) -> Option<&[u8]> {
1447 for e in self.entries.iter_mut() {
1448 if e.0 == key && e.2 {
1449 e.3 += 1;
1450 self.total_hits += 1;
1451 return Some(&e.1);
1452 }
1453 }
1454 self.total_misses += 1;
1455 None
1456 }
1457 #[allow(dead_code)]
1458 pub fn put(&mut self, key: u64, data: Vec<u8>) {
1459 if self.entries.len() >= self.cap {
1460 self.entries.retain(|e| e.2);
1461 if self.entries.len() >= self.cap {
1462 self.entries.remove(0);
1463 }
1464 }
1465 self.entries.push((key, data, true, 0));
1466 }
1467 #[allow(dead_code)]
1468 pub fn invalidate(&mut self) {
1469 for e in self.entries.iter_mut() {
1470 e.2 = false;
1471 }
1472 }
1473 #[allow(dead_code)]
1474 pub fn hit_rate(&self) -> f64 {
1475 let t = self.total_hits + self.total_misses;
1476 if t == 0 {
1477 0.0
1478 } else {
1479 self.total_hits as f64 / t as f64
1480 }
1481 }
1482 #[allow(dead_code)]
1483 pub fn live_count(&self) -> usize {
1484 self.entries.iter().filter(|e| e.2).count()
1485 }
1486}
1487#[derive(Debug, Clone)]
1489pub struct ChapelRecord {
1490 pub name: String,
1492 pub fields: Vec<ChapelField>,
1494 pub methods: Vec<ChapelProc>,
1496 pub type_params: Vec<String>,
1498}
1499impl ChapelRecord {
1500 pub fn new(name: impl Into<String>) -> Self {
1502 ChapelRecord {
1503 name: name.into(),
1504 fields: vec![],
1505 methods: vec![],
1506 type_params: vec![],
1507 }
1508 }
1509 pub fn add_field(&mut self, field: ChapelField) {
1511 self.fields.push(field);
1512 }
1513 pub fn add_method(&mut self, method: ChapelProc) {
1515 self.methods.push(method);
1516 }
1517}
1518#[allow(dead_code)]
1519#[derive(Debug, Clone)]
1520pub struct ChplLivenessInfo {
1521 pub live_in: Vec<std::collections::HashSet<u32>>,
1522 pub live_out: Vec<std::collections::HashSet<u32>>,
1523 pub defs: Vec<std::collections::HashSet<u32>>,
1524 pub uses: Vec<std::collections::HashSet<u32>>,
1525}
1526impl ChplLivenessInfo {
1527 #[allow(dead_code)]
1528 pub fn new(block_count: usize) -> Self {
1529 ChplLivenessInfo {
1530 live_in: vec![std::collections::HashSet::new(); block_count],
1531 live_out: vec![std::collections::HashSet::new(); block_count],
1532 defs: vec![std::collections::HashSet::new(); block_count],
1533 uses: vec![std::collections::HashSet::new(); block_count],
1534 }
1535 }
1536 #[allow(dead_code)]
1537 pub fn add_def(&mut self, block: usize, var: u32) {
1538 if block < self.defs.len() {
1539 self.defs[block].insert(var);
1540 }
1541 }
1542 #[allow(dead_code)]
1543 pub fn add_use(&mut self, block: usize, var: u32) {
1544 if block < self.uses.len() {
1545 self.uses[block].insert(var);
1546 }
1547 }
1548 #[allow(dead_code)]
1549 pub fn is_live_in(&self, block: usize, var: u32) -> bool {
1550 self.live_in
1551 .get(block)
1552 .map(|s| s.contains(&var))
1553 .unwrap_or(false)
1554 }
1555 #[allow(dead_code)]
1556 pub fn is_live_out(&self, block: usize, var: u32) -> bool {
1557 self.live_out
1558 .get(block)
1559 .map(|s| s.contains(&var))
1560 .unwrap_or(false)
1561 }
1562}
1563#[allow(dead_code)]
1564#[derive(Debug, Clone)]
1565pub struct ChplDominatorTree {
1566 pub idom: Vec<Option<u32>>,
1567 pub dom_children: Vec<Vec<u32>>,
1568 pub dom_depth: Vec<u32>,
1569}
1570impl ChplDominatorTree {
1571 #[allow(dead_code)]
1572 pub fn new(size: usize) -> Self {
1573 ChplDominatorTree {
1574 idom: vec![None; size],
1575 dom_children: vec![Vec::new(); size],
1576 dom_depth: vec![0; size],
1577 }
1578 }
1579 #[allow(dead_code)]
1580 pub fn set_idom(&mut self, node: usize, idom: u32) {
1581 self.idom[node] = Some(idom);
1582 }
1583 #[allow(dead_code)]
1584 pub fn dominates(&self, a: usize, b: usize) -> bool {
1585 if a == b {
1586 return true;
1587 }
1588 let mut cur = b;
1589 loop {
1590 match self.idom[cur] {
1591 Some(parent) if parent as usize == a => return true,
1592 Some(parent) if parent as usize == cur => return false,
1593 Some(parent) => cur = parent as usize,
1594 None => return false,
1595 }
1596 }
1597 }
1598 #[allow(dead_code)]
1599 pub fn depth(&self, node: usize) -> u32 {
1600 self.dom_depth.get(node).copied().unwrap_or(0)
1601 }
1602}
1603#[derive(Debug, Clone)]
1605pub struct ChapelParam {
1606 pub name: String,
1608 pub ty: Option<ChapelType>,
1610 pub intent: Option<ChapelIntent>,
1612 pub default: Option<ChapelExpr>,
1614}
1615impl ChapelParam {
1616 pub fn simple(name: impl Into<String>, ty: ChapelType) -> Self {
1618 ChapelParam {
1619 name: name.into(),
1620 ty: Some(ty),
1621 intent: None,
1622 default: None,
1623 }
1624 }
1625 pub fn with_intent(name: impl Into<String>, ty: ChapelType, intent: ChapelIntent) -> Self {
1627 ChapelParam {
1628 name: name.into(),
1629 ty: Some(ty),
1630 intent: Some(intent),
1631 default: None,
1632 }
1633 }
1634}
1635#[allow(dead_code)]
1636#[derive(Debug, Clone, Default)]
1637pub struct ChplPassStats {
1638 pub total_runs: u32,
1639 pub successful_runs: u32,
1640 pub total_changes: u64,
1641 pub time_ms: u64,
1642 pub iterations_used: u32,
1643}
1644impl ChplPassStats {
1645 #[allow(dead_code)]
1646 pub fn new() -> Self {
1647 Self::default()
1648 }
1649 #[allow(dead_code)]
1650 pub fn record_run(&mut self, changes: u64, time_ms: u64, iterations: u32) {
1651 self.total_runs += 1;
1652 self.successful_runs += 1;
1653 self.total_changes += changes;
1654 self.time_ms += time_ms;
1655 self.iterations_used = iterations;
1656 }
1657 #[allow(dead_code)]
1658 pub fn average_changes_per_run(&self) -> f64 {
1659 if self.total_runs == 0 {
1660 return 0.0;
1661 }
1662 self.total_changes as f64 / self.total_runs as f64
1663 }
1664 #[allow(dead_code)]
1665 pub fn success_rate(&self) -> f64 {
1666 if self.total_runs == 0 {
1667 return 0.0;
1668 }
1669 self.successful_runs as f64 / self.total_runs as f64
1670 }
1671 #[allow(dead_code)]
1672 pub fn format_summary(&self) -> String {
1673 format!(
1674 "Runs: {}/{}, Changes: {}, Time: {}ms",
1675 self.successful_runs, self.total_runs, self.total_changes, self.time_ms
1676 )
1677 }
1678}
1679#[allow(dead_code)]
1681#[derive(Debug, Clone, Default)]
1682pub struct ChapelExtLiveness {
1683 pub live_in: Vec<Vec<usize>>,
1684 pub live_out: Vec<Vec<usize>>,
1685 pub defs: Vec<Vec<usize>>,
1686 pub uses: Vec<Vec<usize>>,
1687}
1688impl ChapelExtLiveness {
1689 #[allow(dead_code)]
1690 pub fn new(n: usize) -> Self {
1691 Self {
1692 live_in: vec![Vec::new(); n],
1693 live_out: vec![Vec::new(); n],
1694 defs: vec![Vec::new(); n],
1695 uses: vec![Vec::new(); n],
1696 }
1697 }
1698 #[allow(dead_code)]
1699 pub fn live_in(&self, b: usize, v: usize) -> bool {
1700 self.live_in.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1701 }
1702 #[allow(dead_code)]
1703 pub fn live_out(&self, b: usize, v: usize) -> bool {
1704 self.live_out
1705 .get(b)
1706 .map(|s| s.contains(&v))
1707 .unwrap_or(false)
1708 }
1709 #[allow(dead_code)]
1710 pub fn add_def(&mut self, b: usize, v: usize) {
1711 if let Some(s) = self.defs.get_mut(b) {
1712 if !s.contains(&v) {
1713 s.push(v);
1714 }
1715 }
1716 }
1717 #[allow(dead_code)]
1718 pub fn add_use(&mut self, b: usize, v: usize) {
1719 if let Some(s) = self.uses.get_mut(b) {
1720 if !s.contains(&v) {
1721 s.push(v);
1722 }
1723 }
1724 }
1725 #[allow(dead_code)]
1726 pub fn var_is_used_in_block(&self, b: usize, v: usize) -> bool {
1727 self.uses.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1728 }
1729 #[allow(dead_code)]
1730 pub fn var_is_def_in_block(&self, b: usize, v: usize) -> bool {
1731 self.defs.get(b).map(|s| s.contains(&v)).unwrap_or(false)
1732 }
1733}
1734#[derive(Debug, Clone)]
1736pub struct ChapelProc {
1737 pub name: String,
1739 pub params: Vec<ChapelParam>,
1741 pub return_type: Option<ChapelType>,
1743 pub body: Vec<ChapelStmt>,
1745 pub is_iter: bool,
1747 pub is_inline: bool,
1749 pub is_override: bool,
1751 pub is_operator: bool,
1753 pub where_clause: Option<String>,
1755}
1756impl ChapelProc {
1757 pub fn new(
1759 name: impl Into<String>,
1760 params: Vec<ChapelParam>,
1761 return_type: Option<ChapelType>,
1762 body: Vec<ChapelStmt>,
1763 ) -> Self {
1764 ChapelProc {
1765 name: name.into(),
1766 params,
1767 return_type,
1768 body,
1769 is_iter: false,
1770 is_inline: false,
1771 is_override: false,
1772 is_operator: false,
1773 where_clause: None,
1774 }
1775 }
1776 pub fn as_iter(mut self) -> Self {
1778 self.is_iter = true;
1779 self
1780 }
1781 pub fn as_inline(mut self) -> Self {
1783 self.is_inline = true;
1784 self
1785 }
1786 pub fn with_where(mut self, clause: impl Into<String>) -> Self {
1788 self.where_clause = Some(clause.into());
1789 self
1790 }
1791}
1792#[derive(Debug, Clone)]
1794pub struct ChapelField {
1795 pub name: String,
1797 pub ty: ChapelType,
1799 pub is_const: bool,
1801 pub default: Option<ChapelExpr>,
1803}
1804#[allow(dead_code)]
1805#[derive(Debug, Clone)]
1806pub struct ChplCacheEntry {
1807 pub key: String,
1808 pub data: Vec<u8>,
1809 pub timestamp: u64,
1810 pub valid: bool,
1811}
1812#[allow(dead_code)]
1814#[derive(Debug, Clone)]
1815pub struct ChapelExtDomTree {
1816 pub(super) idom: Vec<Option<usize>>,
1817 pub(super) children: Vec<Vec<usize>>,
1818 pub(super) depth: Vec<usize>,
1819}
1820impl ChapelExtDomTree {
1821 #[allow(dead_code)]
1822 pub fn new(n: usize) -> Self {
1823 Self {
1824 idom: vec![None; n],
1825 children: vec![Vec::new(); n],
1826 depth: vec![0; n],
1827 }
1828 }
1829 #[allow(dead_code)]
1830 pub fn set_idom(&mut self, node: usize, dom: usize) {
1831 if node < self.idom.len() {
1832 self.idom[node] = Some(dom);
1833 if dom < self.children.len() {
1834 self.children[dom].push(node);
1835 }
1836 self.depth[node] = if dom < self.depth.len() {
1837 self.depth[dom] + 1
1838 } else {
1839 1
1840 };
1841 }
1842 }
1843 #[allow(dead_code)]
1844 pub fn dominates(&self, a: usize, mut b: usize) -> bool {
1845 if a == b {
1846 return true;
1847 }
1848 let n = self.idom.len();
1849 for _ in 0..n {
1850 match self.idom.get(b).copied().flatten() {
1851 None => return false,
1852 Some(p) if p == a => return true,
1853 Some(p) if p == b => return false,
1854 Some(p) => b = p,
1855 }
1856 }
1857 false
1858 }
1859 #[allow(dead_code)]
1860 pub fn children_of(&self, n: usize) -> &[usize] {
1861 self.children.get(n).map(|v| v.as_slice()).unwrap_or(&[])
1862 }
1863 #[allow(dead_code)]
1864 pub fn depth_of(&self, n: usize) -> usize {
1865 self.depth.get(n).copied().unwrap_or(0)
1866 }
1867 #[allow(dead_code)]
1868 pub fn lca(&self, mut a: usize, mut b: usize) -> usize {
1869 let n = self.idom.len();
1870 for _ in 0..(2 * n) {
1871 if a == b {
1872 return a;
1873 }
1874 if self.depth_of(a) > self.depth_of(b) {
1875 a = self.idom.get(a).and_then(|x| *x).unwrap_or(a);
1876 } else {
1877 b = self.idom.get(b).and_then(|x| *x).unwrap_or(b);
1878 }
1879 }
1880 0
1881 }
1882}
1883#[allow(dead_code)]
1884#[derive(Debug, Clone)]
1885pub struct ChplWorklist {
1886 pub(super) items: std::collections::VecDeque<u32>,
1887 pub(super) in_worklist: std::collections::HashSet<u32>,
1888}
1889impl ChplWorklist {
1890 #[allow(dead_code)]
1891 pub fn new() -> Self {
1892 ChplWorklist {
1893 items: std::collections::VecDeque::new(),
1894 in_worklist: std::collections::HashSet::new(),
1895 }
1896 }
1897 #[allow(dead_code)]
1898 pub fn push(&mut self, item: u32) -> bool {
1899 if self.in_worklist.insert(item) {
1900 self.items.push_back(item);
1901 true
1902 } else {
1903 false
1904 }
1905 }
1906 #[allow(dead_code)]
1907 pub fn pop(&mut self) -> Option<u32> {
1908 let item = self.items.pop_front()?;
1909 self.in_worklist.remove(&item);
1910 Some(item)
1911 }
1912 #[allow(dead_code)]
1913 pub fn is_empty(&self) -> bool {
1914 self.items.is_empty()
1915 }
1916 #[allow(dead_code)]
1917 pub fn len(&self) -> usize {
1918 self.items.len()
1919 }
1920 #[allow(dead_code)]
1921 pub fn contains(&self, item: u32) -> bool {
1922 self.in_worklist.contains(&item)
1923 }
1924}
1925#[allow(dead_code)]
1927#[derive(Debug, Clone, Default)]
1928pub struct ChapelExtPassStats {
1929 pub iterations: usize,
1930 pub changed: bool,
1931 pub nodes_visited: usize,
1932 pub nodes_modified: usize,
1933 pub time_ms: u64,
1934 pub memory_bytes: usize,
1935 pub errors: usize,
1936}
1937impl ChapelExtPassStats {
1938 #[allow(dead_code)]
1939 pub fn new() -> Self {
1940 Self::default()
1941 }
1942 #[allow(dead_code)]
1943 pub fn visit(&mut self) {
1944 self.nodes_visited += 1;
1945 }
1946 #[allow(dead_code)]
1947 pub fn modify(&mut self) {
1948 self.nodes_modified += 1;
1949 self.changed = true;
1950 }
1951 #[allow(dead_code)]
1952 pub fn iterate(&mut self) {
1953 self.iterations += 1;
1954 }
1955 #[allow(dead_code)]
1956 pub fn error(&mut self) {
1957 self.errors += 1;
1958 }
1959 #[allow(dead_code)]
1960 pub fn efficiency(&self) -> f64 {
1961 if self.nodes_visited == 0 {
1962 0.0
1963 } else {
1964 self.nodes_modified as f64 / self.nodes_visited as f64
1965 }
1966 }
1967 #[allow(dead_code)]
1968 pub fn merge(&mut self, o: &ChapelExtPassStats) {
1969 self.iterations += o.iterations;
1970 self.changed |= o.changed;
1971 self.nodes_visited += o.nodes_visited;
1972 self.nodes_modified += o.nodes_modified;
1973 self.time_ms += o.time_ms;
1974 self.memory_bytes = self.memory_bytes.max(o.memory_bytes);
1975 self.errors += o.errors;
1976 }
1977}
1978#[derive(Debug, Clone)]
1980pub struct ChapelClass {
1981 pub name: String,
1983 pub parent: Option<String>,
1985 pub fields: Vec<ChapelField>,
1987 pub methods: Vec<ChapelProc>,
1989 pub type_params: Vec<String>,
1991}
1992impl ChapelClass {
1993 pub fn new(name: impl Into<String>) -> Self {
1995 ChapelClass {
1996 name: name.into(),
1997 parent: None,
1998 fields: vec![],
1999 methods: vec![],
2000 type_params: vec![],
2001 }
2002 }
2003 pub fn with_parent(mut self, parent: impl Into<String>) -> Self {
2005 self.parent = Some(parent.into());
2006 self
2007 }
2008 pub fn add_field(&mut self, field: ChapelField) {
2010 self.fields.push(field);
2011 }
2012 pub fn add_method(&mut self, method: ChapelProc) {
2014 self.methods.push(method);
2015 }
2016}
2017#[allow(dead_code)]
2019#[derive(Debug, Clone)]
2020pub struct ChapelExtPassConfig {
2021 pub name: String,
2022 pub phase: ChapelExtPassPhase,
2023 pub enabled: bool,
2024 pub max_iterations: usize,
2025 pub debug: u32,
2026 pub timeout_ms: Option<u64>,
2027}
2028impl ChapelExtPassConfig {
2029 #[allow(dead_code)]
2030 pub fn new(name: impl Into<String>) -> Self {
2031 Self {
2032 name: name.into(),
2033 phase: ChapelExtPassPhase::Middle,
2034 enabled: true,
2035 max_iterations: 100,
2036 debug: 0,
2037 timeout_ms: None,
2038 }
2039 }
2040 #[allow(dead_code)]
2041 pub fn with_phase(mut self, phase: ChapelExtPassPhase) -> Self {
2042 self.phase = phase;
2043 self
2044 }
2045 #[allow(dead_code)]
2046 pub fn with_max_iter(mut self, n: usize) -> Self {
2047 self.max_iterations = n;
2048 self
2049 }
2050 #[allow(dead_code)]
2051 pub fn with_debug(mut self, d: u32) -> Self {
2052 self.debug = d;
2053 self
2054 }
2055 #[allow(dead_code)]
2056 pub fn disabled(mut self) -> Self {
2057 self.enabled = false;
2058 self
2059 }
2060 #[allow(dead_code)]
2061 pub fn with_timeout(mut self, ms: u64) -> Self {
2062 self.timeout_ms = Some(ms);
2063 self
2064 }
2065 #[allow(dead_code)]
2066 pub fn is_debug_enabled(&self) -> bool {
2067 self.debug > 0
2068 }
2069}
2070#[allow(dead_code)]
2071#[derive(Debug, Clone, PartialEq)]
2072pub enum ChplPassPhase {
2073 Analysis,
2074 Transformation,
2075 Verification,
2076 Cleanup,
2077}
2078impl ChplPassPhase {
2079 #[allow(dead_code)]
2080 pub fn name(&self) -> &str {
2081 match self {
2082 ChplPassPhase::Analysis => "analysis",
2083 ChplPassPhase::Transformation => "transformation",
2084 ChplPassPhase::Verification => "verification",
2085 ChplPassPhase::Cleanup => "cleanup",
2086 }
2087 }
2088 #[allow(dead_code)]
2089 pub fn is_modifying(&self) -> bool {
2090 matches!(self, ChplPassPhase::Transformation | ChplPassPhase::Cleanup)
2091 }
2092}
2093#[derive(Debug, Clone)]
2095pub struct ChapelModule {
2096 pub name: Option<String>,
2098 pub uses: Vec<String>,
2100 pub requires: Vec<String>,
2102 pub globals: Vec<(String, ChapelType, ChapelExpr)>,
2104 pub configs: Vec<(String, ChapelType, Option<ChapelExpr>)>,
2106 pub procs: Vec<ChapelProc>,
2108 pub records: Vec<ChapelRecord>,
2110 pub classes: Vec<ChapelClass>,
2112 pub submodules: Vec<ChapelModule>,
2114 pub doc: Option<String>,
2116}
2117impl ChapelModule {
2118 pub fn new() -> Self {
2120 ChapelModule {
2121 name: None,
2122 uses: vec![],
2123 requires: vec![],
2124 globals: vec![],
2125 configs: vec![],
2126 procs: vec![],
2127 records: vec![],
2128 classes: vec![],
2129 submodules: vec![],
2130 doc: None,
2131 }
2132 }
2133 pub fn named(name: impl Into<String>) -> Self {
2135 let mut m = ChapelModule::new();
2136 m.name = Some(name.into());
2137 m
2138 }
2139 pub fn add_use(&mut self, name: impl Into<String>) {
2141 self.uses.push(name.into());
2142 }
2143 pub fn add_require(&mut self, path: impl Into<String>) {
2145 self.requires.push(path.into());
2146 }
2147 pub fn add_global(&mut self, name: impl Into<String>, ty: ChapelType, expr: ChapelExpr) {
2149 self.globals.push((name.into(), ty, expr));
2150 }
2151 pub fn add_config(
2153 &mut self,
2154 name: impl Into<String>,
2155 ty: ChapelType,
2156 default: Option<ChapelExpr>,
2157 ) {
2158 self.configs.push((name.into(), ty, default));
2159 }
2160 pub fn add_proc(&mut self, proc: ChapelProc) {
2162 self.procs.push(proc);
2163 }
2164 pub fn add_record(&mut self, rec: ChapelRecord) {
2166 self.records.push(rec);
2167 }
2168 pub fn add_class(&mut self, cls: ChapelClass) {
2170 self.classes.push(cls);
2171 }
2172 pub fn set_doc(&mut self, doc: impl Into<String>) {
2174 self.doc = Some(doc.into());
2175 }
2176}
2177#[allow(dead_code)]
2179#[derive(Debug, Clone)]
2180pub struct ChapelExtWorklist {
2181 pub(super) items: std::collections::VecDeque<usize>,
2182 pub(super) present: Vec<bool>,
2183}
2184impl ChapelExtWorklist {
2185 #[allow(dead_code)]
2186 pub fn new(capacity: usize) -> Self {
2187 Self {
2188 items: std::collections::VecDeque::new(),
2189 present: vec![false; capacity],
2190 }
2191 }
2192 #[allow(dead_code)]
2193 pub fn push(&mut self, id: usize) {
2194 if id < self.present.len() && !self.present[id] {
2195 self.present[id] = true;
2196 self.items.push_back(id);
2197 }
2198 }
2199 #[allow(dead_code)]
2200 pub fn push_front(&mut self, id: usize) {
2201 if id < self.present.len() && !self.present[id] {
2202 self.present[id] = true;
2203 self.items.push_front(id);
2204 }
2205 }
2206 #[allow(dead_code)]
2207 pub fn pop(&mut self) -> Option<usize> {
2208 let id = self.items.pop_front()?;
2209 if id < self.present.len() {
2210 self.present[id] = false;
2211 }
2212 Some(id)
2213 }
2214 #[allow(dead_code)]
2215 pub fn is_empty(&self) -> bool {
2216 self.items.is_empty()
2217 }
2218 #[allow(dead_code)]
2219 pub fn len(&self) -> usize {
2220 self.items.len()
2221 }
2222 #[allow(dead_code)]
2223 pub fn contains(&self, id: usize) -> bool {
2224 id < self.present.len() && self.present[id]
2225 }
2226 #[allow(dead_code)]
2227 pub fn drain_all(&mut self) -> Vec<usize> {
2228 let v: Vec<usize> = self.items.drain(..).collect();
2229 for &id in &v {
2230 if id < self.present.len() {
2231 self.present[id] = false;
2232 }
2233 }
2234 v
2235 }
2236}
2237#[allow(dead_code)]
2239#[derive(Debug, Clone)]
2240pub struct ChapelExtDepGraph {
2241 pub(super) n: usize,
2242 pub(super) adj: Vec<Vec<usize>>,
2243 pub(super) rev: Vec<Vec<usize>>,
2244 pub(super) edge_count: usize,
2245}
2246impl ChapelExtDepGraph {
2247 #[allow(dead_code)]
2248 pub fn new(n: usize) -> Self {
2249 Self {
2250 n,
2251 adj: vec![Vec::new(); n],
2252 rev: vec![Vec::new(); n],
2253 edge_count: 0,
2254 }
2255 }
2256 #[allow(dead_code)]
2257 pub fn add_edge(&mut self, from: usize, to: usize) {
2258 if from < self.n && to < self.n {
2259 if !self.adj[from].contains(&to) {
2260 self.adj[from].push(to);
2261 self.rev[to].push(from);
2262 self.edge_count += 1;
2263 }
2264 }
2265 }
2266 #[allow(dead_code)]
2267 pub fn succs(&self, n: usize) -> &[usize] {
2268 self.adj.get(n).map(|v| v.as_slice()).unwrap_or(&[])
2269 }
2270 #[allow(dead_code)]
2271 pub fn preds(&self, n: usize) -> &[usize] {
2272 self.rev.get(n).map(|v| v.as_slice()).unwrap_or(&[])
2273 }
2274 #[allow(dead_code)]
2275 pub fn topo_sort(&self) -> Option<Vec<usize>> {
2276 let mut deg: Vec<usize> = (0..self.n).map(|i| self.rev[i].len()).collect();
2277 let mut q: std::collections::VecDeque<usize> =
2278 (0..self.n).filter(|&i| deg[i] == 0).collect();
2279 let mut out = Vec::with_capacity(self.n);
2280 while let Some(u) = q.pop_front() {
2281 out.push(u);
2282 for &v in &self.adj[u] {
2283 deg[v] -= 1;
2284 if deg[v] == 0 {
2285 q.push_back(v);
2286 }
2287 }
2288 }
2289 if out.len() == self.n {
2290 Some(out)
2291 } else {
2292 None
2293 }
2294 }
2295 #[allow(dead_code)]
2296 pub fn has_cycle(&self) -> bool {
2297 self.topo_sort().is_none()
2298 }
2299 #[allow(dead_code)]
2300 pub fn reachable(&self, start: usize) -> Vec<usize> {
2301 let mut vis = vec![false; self.n];
2302 let mut stk = vec![start];
2303 let mut out = Vec::new();
2304 while let Some(u) = stk.pop() {
2305 if u < self.n && !vis[u] {
2306 vis[u] = true;
2307 out.push(u);
2308 for &v in &self.adj[u] {
2309 if !vis[v] {
2310 stk.push(v);
2311 }
2312 }
2313 }
2314 }
2315 out
2316 }
2317 #[allow(dead_code)]
2318 pub fn scc(&self) -> Vec<Vec<usize>> {
2319 let mut visited = vec![false; self.n];
2320 let mut order = Vec::new();
2321 for i in 0..self.n {
2322 if !visited[i] {
2323 let mut stk = vec![(i, 0usize)];
2324 while let Some((u, idx)) = stk.last_mut() {
2325 if !visited[*u] {
2326 visited[*u] = true;
2327 }
2328 if *idx < self.adj[*u].len() {
2329 let v = self.adj[*u][*idx];
2330 *idx += 1;
2331 if !visited[v] {
2332 stk.push((v, 0));
2333 }
2334 } else {
2335 order.push(*u);
2336 stk.pop();
2337 }
2338 }
2339 }
2340 }
2341 let mut comp = vec![usize::MAX; self.n];
2342 let mut components: Vec<Vec<usize>> = Vec::new();
2343 for &start in order.iter().rev() {
2344 if comp[start] == usize::MAX {
2345 let cid = components.len();
2346 let mut component = Vec::new();
2347 let mut stk = vec![start];
2348 while let Some(u) = stk.pop() {
2349 if comp[u] == usize::MAX {
2350 comp[u] = cid;
2351 component.push(u);
2352 for &v in &self.rev[u] {
2353 if comp[v] == usize::MAX {
2354 stk.push(v);
2355 }
2356 }
2357 }
2358 }
2359 components.push(component);
2360 }
2361 }
2362 components
2363 }
2364 #[allow(dead_code)]
2365 pub fn node_count(&self) -> usize {
2366 self.n
2367 }
2368 #[allow(dead_code)]
2369 pub fn edge_count(&self) -> usize {
2370 self.edge_count
2371 }
2372}
2373#[allow(dead_code)]
2375#[derive(Debug, Default)]
2376pub struct ChapelExtPassRegistry {
2377 pub(super) configs: Vec<ChapelExtPassConfig>,
2378 pub(super) stats: Vec<ChapelExtPassStats>,
2379}
2380impl ChapelExtPassRegistry {
2381 #[allow(dead_code)]
2382 pub fn new() -> Self {
2383 Self::default()
2384 }
2385 #[allow(dead_code)]
2386 pub fn register(&mut self, c: ChapelExtPassConfig) {
2387 self.stats.push(ChapelExtPassStats::new());
2388 self.configs.push(c);
2389 }
2390 #[allow(dead_code)]
2391 pub fn len(&self) -> usize {
2392 self.configs.len()
2393 }
2394 #[allow(dead_code)]
2395 pub fn is_empty(&self) -> bool {
2396 self.configs.is_empty()
2397 }
2398 #[allow(dead_code)]
2399 pub fn get(&self, i: usize) -> Option<&ChapelExtPassConfig> {
2400 self.configs.get(i)
2401 }
2402 #[allow(dead_code)]
2403 pub fn get_stats(&self, i: usize) -> Option<&ChapelExtPassStats> {
2404 self.stats.get(i)
2405 }
2406 #[allow(dead_code)]
2407 pub fn enabled_passes(&self) -> Vec<&ChapelExtPassConfig> {
2408 self.configs.iter().filter(|c| c.enabled).collect()
2409 }
2410 #[allow(dead_code)]
2411 pub fn passes_in_phase(&self, ph: &ChapelExtPassPhase) -> Vec<&ChapelExtPassConfig> {
2412 self.configs
2413 .iter()
2414 .filter(|c| c.enabled && &c.phase == ph)
2415 .collect()
2416 }
2417 #[allow(dead_code)]
2418 pub fn total_nodes_visited(&self) -> usize {
2419 self.stats.iter().map(|s| s.nodes_visited).sum()
2420 }
2421 #[allow(dead_code)]
2422 pub fn any_changed(&self) -> bool {
2423 self.stats.iter().any(|s| s.changed)
2424 }
2425}