calyx_opt/passes_experimental/
register_unsharing.rs1use crate::analysis::reaching_defns::{
4 GroupOrInvoke, ReachingDefinitionAnalysis,
5};
6use crate::traversal::{Action, Named, VisResult, Visitor};
7use calyx_ir::{self as ir, Builder, LibrarySignatures, rewriter};
8use std::collections::HashMap;
9
10#[derive(Default)]
38pub struct RegisterUnsharing {
39 bookkeeper: Bookkeeper,
40}
41
42impl Named for RegisterUnsharing {
43 fn name() -> &'static str {
44 "register-unsharing"
45 }
46
47 fn description() -> &'static str {
48 "Split apart shared values into separate registers"
49 }
50}
51
52type RewriteMap = HashMap<ir::Id, rewriter::RewriteMap<ir::Cell>>;
53
54#[derive(Default)]
56struct Bookkeeper {
57 analysis: ReachingDefinitionAnalysis,
58 widths: HashMap<ir::Id, u64>,
59 invoke_map: RewriteMap,
60}
61
62impl Bookkeeper {
63 fn new(comp: &ir::Component) -> Self {
65 let widths = comp
67 .cells
68 .iter()
69 .filter_map(|c| {
70 if let ir::CellType::Primitive { name, .. } =
71 &c.borrow().prototype
72 && name == "std_reg"
73 && let Some(in_port) = c.borrow().find("in")
74 {
75 return Some((c.borrow().name(), in_port.borrow().width));
76 }
77 None
78 })
79 .collect();
80
81 Self {
82 widths,
83 analysis: ReachingDefinitionAnalysis::new(&comp.control.borrow()),
84 invoke_map: HashMap::new(),
85 }
86 }
87
88 fn create_new_regs(
100 &mut self,
101 builder: &mut Builder,
102 ) -> Vec<(ir::Id, ir::Id, Vec<GroupOrInvoke>)> {
103 let overlap = self
104 .analysis
105 .calculate_overlap(builder.component.continuous_assignments.iter());
106
107 let mut rename_list = vec![];
108
109 for (name, sets) in &overlap {
110 if sets.len() > 1 {
111 for defs in &sets[1..] {
112 let new_name = builder
113 .add_primitive(
114 format!("unshr_{name}"),
115 "std_reg",
116 &[*self.widths.get(name).unwrap()],
117 )
118 .borrow()
119 .name();
120 rename_list.push((
121 new_name,
122 *name,
123 defs.iter()
124 .map(|(_, groupname)| groupname.clone())
125 .collect(),
126 ));
127 }
128 }
129 }
130 rename_list
131 }
132
133 fn rename(
134 &mut self,
135 comp: &mut ir::Component,
136 rename_list: &[(ir::Id, ir::Id, Vec<GroupOrInvoke>)],
137 ) {
138 let mut grp_map: RewriteMap = HashMap::new();
139 let mut invoke_map: RewriteMap = HashMap::new();
140 for (new_name, old_name, grouplist) in rename_list {
141 for group_or_invoke in grouplist {
142 let name = *old_name;
143 let cell = comp.find_cell(*new_name).unwrap();
144 match group_or_invoke {
145 GroupOrInvoke::Group(group) => {
146 grp_map.entry(*group).or_default().insert(name, cell);
147 }
148 GroupOrInvoke::Invoke(invoke) => {
149 invoke_map
150 .entry(*invoke)
151 .or_default()
152 .insert(name, cell);
153 }
154 }
155 }
156 }
157
158 for (grp, rename_cells) in grp_map {
159 let group_ref = comp.find_group(grp).unwrap();
160 let mut group = group_ref.borrow_mut();
161 let rewriter = ir::Rewriter {
162 cell_map: rename_cells,
163 ..Default::default()
164 };
165 group
166 .assignments
167 .iter_mut()
168 .for_each(|assign| assign.for_each_port(|p| rewriter.get(p)));
169 }
170
171 self.invoke_map = invoke_map;
172 }
173}
174
175impl Visitor for RegisterUnsharing {
176 fn start(
177 &mut self,
178 comp: &mut ir::Component,
179 sigs: &LibrarySignatures,
180 _comps: &[ir::Component],
181 ) -> VisResult {
182 self.bookkeeper = Bookkeeper::new(comp);
183 let mut builder = Builder::new(comp, sigs);
184 let rename_list = self.bookkeeper.create_new_regs(&mut builder);
186 self.bookkeeper.rename(comp, &rename_list);
188 Ok(Action::Continue)
189 }
190
191 fn invoke(
192 &mut self,
193 invoke: &mut ir::Invoke,
194 _comp: &mut ir::Component,
195 _sigs: &LibrarySignatures,
196 _comps: &[ir::Component],
197 ) -> VisResult {
198 let book = &mut self.bookkeeper;
199
200 if let Some(name) = book.analysis.meta.fetch_label(invoke) {
201 if let Some(rename_vec) = book.invoke_map.get_mut(name) {
203 let cell_map = std::mem::take(rename_vec);
204 let rewriter = ir::Rewriter {
205 cell_map,
206 ..Default::default()
207 };
208 rewriter.rewrite_invoke(invoke);
209 *rename_vec = rewriter.cell_map;
210 }
211 }
212
213 Ok(Action::Continue)
214 }
215
216 fn static_invoke(
217 &mut self,
218 invoke: &mut ir::StaticInvoke,
219 _comp: &mut ir::Component,
220 _sigs: &LibrarySignatures,
221 _comps: &[ir::Component],
222 ) -> VisResult {
223 let book = &mut self.bookkeeper;
224
225 if let Some(name) = book.analysis.meta.fetch_label_static(invoke) {
226 if let Some(rename_vec) = book.invoke_map.get_mut(name) {
228 let cell_map = std::mem::take(rename_vec);
229 let rewriter = ir::Rewriter {
230 cell_map,
231 ..Default::default()
232 };
233 rewriter.rewrite_static_invoke(invoke);
234 *rename_vec = rewriter.cell_map;
235 }
236 }
237
238 Ok(Action::Continue)
239 }
240}