calyx_opt/passes_experimental/
par_to_seq.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use crate::analysis;
use crate::traversal::{
    Action, ConstructVisitor, Named, ParseVal, PassOpt, VisResult, Visitor,
};
use calyx_ir::{self as ir, LibrarySignatures};
use calyx_utils::CalyxResult;

/// Transforms all `par` into `seq`. When the `correctness-checking` option is on,
/// uses [analysis::ControlOrder] to get a sequentialization of `par` such that
/// the program still computes the same value, and errors out when
/// there is no such sequentialization.
///
/// # Example
/// ```
/// par {
///     par { A; B }
///     C;
/// }
/// ```
/// into
/// ```
/// seq { seq { A; B } C; }
/// ```
///
/// To remove uneccessarily nested `par` blocks, run collapse-control.
pub struct ParToSeq {
    /// Guarantees correctness on shared reads and writes by erroring out
    /// if sequentialization where program still computes the same value doesn't exist.
    correctness_checking: bool,
}

impl Named for ParToSeq {
    fn name() -> &'static str {
        "par-to-seq"
    }

    fn description() -> &'static str {
        "Transform `par` blocks to `seq`"
    }

    fn opts() -> Vec<crate::traversal::PassOpt> {
        vec![PassOpt::new(
            "correctness-checking",
            "Errors out when dataflow dependencies cannot be preserved.",
            ParseVal::Bool(false),
            PassOpt::parse_bool,
        )]
    }
}

impl ConstructVisitor for ParToSeq {
    fn from(ctx: &ir::Context) -> CalyxResult<Self>
    where
        Self: Sized + Named,
    {
        let opts = Self::get_opts(ctx);

        Ok(ParToSeq {
            correctness_checking: opts[&"correctness-checking"].bool(),
        })
    }

    fn clear_data(&mut self) {
        /* All data can be transferred between components */
    }
}

impl Visitor for ParToSeq {
    /// Collapse par { par { A }; B } into par { A; B }.
    fn finish_par(
        &mut self,
        s: &mut ir::Par,
        _comp: &mut ir::Component,
        _c: &LibrarySignatures,
        _comps: &[ir::Component],
    ) -> VisResult {
        let par = if self.correctness_checking {
            let total_order = analysis::ControlOrder::<true>::get_total_order(
                s.stmts.drain(..),
            )?;
            ir::Control::seq(total_order)
        } else {
            ir::Control::seq(s.stmts.drain(..).collect())
        };
        Ok(Action::change(par))
    }
}