calyx_opt/analysis/
control_id.rs

1use calyx_ir as ir;
2
3const NODE_ID: ir::Attribute =
4    ir::Attribute::Internal(ir::InternalAttr::NODE_ID);
5const BEGIN_ID: ir::Attribute =
6    ir::Attribute::Internal(ir::InternalAttr::BEGIN_ID);
7const END_ID: ir::Attribute = ir::Attribute::Internal(ir::InternalAttr::END_ID);
8
9/// Adding "NODE_ID", "BEGIN_ID", and "END_ID" attribute to control statement
10pub struct ControlId;
11
12impl ControlId {
13    fn compute_unique_ids_static(
14        scon: &mut ir::StaticControl,
15        mut cur_state: u64,
16        two_if_ids: bool,
17    ) -> u64 {
18        match scon {
19            ir::StaticControl::Empty(_) => cur_state,
20            ir::StaticControl::Enable(ir::StaticEnable {
21                attributes, ..
22            })
23            | ir::StaticControl::Invoke(ir::StaticInvoke {
24                attributes, ..
25            }) => {
26                attributes.insert(NODE_ID, cur_state);
27                cur_state + 1
28            }
29            ir::StaticControl::Repeat(ir::StaticRepeat {
30                attributes,
31                body,
32                ..
33            }) => {
34                attributes.insert(NODE_ID, cur_state);
35                cur_state += 1;
36                Self::compute_unique_ids_static(body, cur_state, two_if_ids)
37            }
38            ir::StaticControl::Par(ir::StaticPar {
39                stmts, attributes, ..
40            })
41            | ir::StaticControl::Seq(ir::StaticSeq {
42                stmts, attributes, ..
43            }) => {
44                attributes.insert(NODE_ID, cur_state);
45                cur_state += 1;
46                stmts.iter_mut().for_each(|stmt| {
47                    let new_state = Self::compute_unique_ids_static(
48                        stmt, cur_state, two_if_ids,
49                    );
50                    cur_state = new_state;
51                });
52                cur_state
53            }
54            ir::StaticControl::If(ir::StaticIf {
55                tbranch,
56                fbranch,
57                attributes,
58                ..
59            }) => {
60                if two_if_ids {
61                    attributes.insert(BEGIN_ID, cur_state);
62                    cur_state += 1;
63                    cur_state = Self::compute_unique_ids_static(
64                        tbranch, cur_state, two_if_ids,
65                    );
66                    cur_state = Self::compute_unique_ids_static(
67                        fbranch, cur_state, two_if_ids,
68                    );
69                    attributes.insert(END_ID, cur_state);
70                    cur_state + 1
71                } else {
72                    attributes.insert(NODE_ID, cur_state);
73                    cur_state += 1;
74                    cur_state = Self::compute_unique_ids_static(
75                        tbranch, cur_state, two_if_ids,
76                    );
77                    cur_state = Self::compute_unique_ids_static(
78                        fbranch, cur_state, two_if_ids,
79                    );
80                    cur_state + 1
81                }
82            }
83        }
84    }
85
86    /// Adds the @NODE_ID attribute to all control stmts except emtpy ones.
87    /// If two_if_ids is true, then if statements get a BEGIN_ID and END_ID instead
88    /// of a NODE_ID
89    ///
90    /// ## Example:
91    /// ```
92    /// seq { A; if cond {X} else{Y}; par { C; D; }; E }
93    /// ```
94    ///
95    /// gets the labels (if two_if_ids is):
96    ///
97    /// ```
98    /// @NODE_ID(0)seq {
99    ///   @NODE_ID(1) A;
100    ///   @BEGIN_ID(2) @END_ID(5) if cond {
101    ///     @NODE_ID(3) X
102    ///   }
103    ///   else{
104    ///     @NODE_ID(4) Y
105    ///   }
106    ///   @NODE_ID(6) par {
107    ///     @NODE_ID(7) C;
108    ///     @NODE_ID(8) D;
109    ///   }
110    ///   @NODE_ID(9) E;
111    /// }
112    /// ```
113    /// if two_if_ids were false, the if statement would just get a single NODE_ID
114    pub fn compute_unique_ids(
115        con: &mut ir::Control,
116        mut cur_state: u64,
117        two_if_ids: bool,
118    ) -> u64 {
119        match con {
120            ir::Control::Enable(ir::Enable { attributes, .. })
121            | ir::Control::Invoke(ir::Invoke { attributes, .. }) => {
122                attributes.insert(NODE_ID, cur_state);
123                cur_state + 1
124            }
125            ir::Control::Par(ir::Par {
126                stmts, attributes, ..
127            })
128            | ir::Control::Seq(ir::Seq {
129                stmts, attributes, ..
130            }) => {
131                attributes.insert(NODE_ID, cur_state);
132                cur_state += 1;
133                stmts.iter_mut().for_each(|stmt| {
134                    let new_state =
135                        Self::compute_unique_ids(stmt, cur_state, two_if_ids);
136                    cur_state = new_state;
137                });
138                cur_state
139            }
140            ir::Control::If(ir::If {
141                tbranch,
142                fbranch,
143                attributes,
144                ..
145            }) => {
146                if two_if_ids {
147                    attributes.insert(BEGIN_ID, cur_state);
148                    cur_state += 1;
149                    cur_state = Self::compute_unique_ids(
150                        tbranch, cur_state, two_if_ids,
151                    );
152                    cur_state = Self::compute_unique_ids(
153                        fbranch, cur_state, two_if_ids,
154                    );
155                    attributes.insert(END_ID, cur_state);
156                    cur_state + 1
157                } else {
158                    attributes.insert(NODE_ID, cur_state);
159                    cur_state += 1;
160                    cur_state = Self::compute_unique_ids(
161                        tbranch, cur_state, two_if_ids,
162                    );
163                    cur_state = Self::compute_unique_ids(
164                        fbranch, cur_state, two_if_ids,
165                    );
166                    cur_state + 1
167                }
168            }
169            ir::Control::While(ir::While {
170                body, attributes, ..
171            })
172            | ir::Control::Repeat(ir::Repeat {
173                body, attributes, ..
174            }) => {
175                attributes.insert(NODE_ID, cur_state);
176                cur_state += 1;
177                Self::compute_unique_ids(body, cur_state, two_if_ids)
178            }
179            ir::Control::Static(s) => {
180                Self::compute_unique_ids_static(s, cur_state, two_if_ids)
181            }
182            ir::Control::Empty(_) => cur_state,
183        }
184    }
185
186    // Gets attribute s from c, panics otherwise. Should be used when you know
187    // that c has attribute s.
188    pub fn get_guaranteed_attribute<A>(c: &ir::Control, attr: A) -> u64
189    where
190        A: Into<ir::Attribute>,
191    {
192        c.get_attribute(attr.into()).unwrap_or_else(||unreachable!(
193          "called get_guaranteed_attribute, meaning we had to be sure it had the attribute"
194      ))
195    }
196
197    // Gets attribute s from c, panics otherwise. Should be used when you know
198    // that c has attribute s.
199    pub fn get_guaranteed_attribute_static<A>(
200        sc: &ir::StaticControl,
201        attr: A,
202    ) -> u64
203    where
204        A: Into<ir::Attribute>,
205    {
206        sc.get_attribute(attr.into()).unwrap_or_else(||unreachable!(
207          "called get_guaranteed_attribute_static, meaning we had to be sure it had the attribute"
208      ))
209    }
210
211    // Gets attribute NODE_ID from c
212    pub fn get_guaranteed_id(c: &ir::Control) -> u64 {
213        Self::get_guaranteed_attribute(c, NODE_ID)
214    }
215
216    // Gets attribute NODE_ID from c
217    pub fn get_guaranteed_id_static(sc: &ir::StaticControl) -> u64 {
218        Self::get_guaranteed_attribute_static(sc, NODE_ID)
219    }
220
221    // takes in a static control scon, and adds unique id to each static enable.
222    // Returns cur_state, i.e., what the next enable should be labeled as
223    pub fn add_static_enable_ids_static(
224        scon: &mut ir::StaticControl,
225        mut cur_state: u64,
226    ) -> u64 {
227        match scon {
228            ir::StaticControl::Enable(se) => {
229                se.attributes.insert(NODE_ID, cur_state);
230                cur_state + 1
231            }
232            ir::StaticControl::Invoke(_) | ir::StaticControl::Empty(_) => {
233                cur_state
234            }
235            ir::StaticControl::Par(ir::StaticPar { stmts, .. })
236            | ir::StaticControl::Seq(ir::StaticSeq { stmts, .. }) => {
237                for stmt in stmts {
238                    let new_state =
239                        Self::add_static_enable_ids_static(stmt, cur_state);
240                    cur_state = new_state
241                }
242                cur_state
243            }
244            ir::StaticControl::If(ir::StaticIf {
245                tbranch, fbranch, ..
246            }) => {
247                let mut new_state =
248                    Self::add_static_enable_ids_static(tbranch, cur_state);
249                cur_state = new_state;
250                new_state =
251                    Self::add_static_enable_ids_static(fbranch, cur_state);
252                new_state
253            }
254            ir::StaticControl::Repeat(ir::StaticRepeat { body, .. }) => {
255                Self::add_static_enable_ids_static(body, cur_state)
256            }
257        }
258    }
259
260    // takes in ir::Control `con`, and adds unique id to every static enable within it.
261    // returns u64 `cur_state` that says what the next staticenable should be labeled as.
262    pub fn add_static_enable_ids(
263        con: &mut ir::Control,
264        mut cur_state: u64,
265    ) -> u64 {
266        match con {
267            ir::Control::Enable(_)
268            | ir::Control::Invoke(_)
269            | ir::Control::Empty(_) => cur_state,
270            ir::Control::Par(ir::Par { stmts, .. })
271            | ir::Control::Seq(ir::Seq { stmts, .. }) => {
272                for stmt in stmts {
273                    let new_state =
274                        Self::add_static_enable_ids(stmt, cur_state);
275                    cur_state = new_state
276                }
277                cur_state
278            }
279            ir::Control::If(ir::If {
280                tbranch, fbranch, ..
281            }) => {
282                let mut new_state =
283                    Self::add_static_enable_ids(tbranch, cur_state);
284                cur_state = new_state;
285                new_state = Self::add_static_enable_ids(fbranch, cur_state);
286                new_state
287            }
288            ir::Control::While(ir::While { body, .. })
289            | ir::Control::Repeat(ir::Repeat { body, .. }) => {
290                Self::add_static_enable_ids(body, cur_state)
291            }
292            ir::Control::Static(s) => {
293                Self::add_static_enable_ids_static(s, cur_state)
294            }
295        }
296    }
297
298    // Gets NODE_ID from StaticEnable se, panics otherwise. Should be used when you know
299    // that se has attributes NODE_ID.
300    pub fn get_guaranteed_enable_id(se: &ir::StaticEnable) -> u64 {
301        se.get_attribute(NODE_ID).unwrap_or_else(||unreachable!(
302          "called get_guaranteed_enable_id, meaning we had to be sure it had a NODE_ID attribute"
303      ))
304    }
305}