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 {
73 if name == "std_reg" {
74 if let Some(in_port) = c.borrow().find("in") {
75 return Some((
76 c.borrow().name(),
77 in_port.borrow().width,
78 ));
79 }
80 }
81 }
82 None
83 })
84 .collect();
85
86 Self {
87 widths,
88 analysis: ReachingDefinitionAnalysis::new(&comp.control.borrow()),
89 invoke_map: HashMap::new(),
90 }
91 }
92
93 fn create_new_regs(
105 &mut self,
106 builder: &mut Builder,
107 ) -> Vec<(ir::Id, ir::Id, Vec<GroupOrInvoke>)> {
108 let overlap = self
109 .analysis
110 .calculate_overlap(builder.component.continuous_assignments.iter());
111
112 let mut rename_list = vec![];
113
114 for (name, sets) in &overlap {
115 if sets.len() > 1 {
116 for defs in &sets[1..] {
117 let new_name = builder
118 .add_primitive(
119 format!("unshr_{name}"),
120 "std_reg",
121 &[*self.widths.get(name).unwrap()],
122 )
123 .borrow()
124 .name();
125 rename_list.push((
126 new_name,
127 *name,
128 defs.iter()
129 .map(|(_, groupname)| groupname.clone())
130 .collect(),
131 ));
132 }
133 }
134 }
135 rename_list
136 }
137
138 fn rename(
139 &mut self,
140 comp: &mut ir::Component,
141 rename_list: &[(ir::Id, ir::Id, Vec<GroupOrInvoke>)],
142 ) {
143 let mut grp_map: RewriteMap = HashMap::new();
144 let mut invoke_map: RewriteMap = HashMap::new();
145 for (new_name, old_name, grouplist) in rename_list {
146 for group_or_invoke in grouplist {
147 let name = *old_name;
148 let cell = comp.find_cell(*new_name).unwrap();
149 match group_or_invoke {
150 GroupOrInvoke::Group(group) => {
151 grp_map.entry(*group).or_default().insert(name, cell);
152 }
153 GroupOrInvoke::Invoke(invoke) => {
154 invoke_map
155 .entry(*invoke)
156 .or_default()
157 .insert(name, cell);
158 }
159 }
160 }
161 }
162
163 for (grp, rename_cells) in grp_map {
164 let group_ref = comp.find_group(grp).unwrap();
165 let mut group = group_ref.borrow_mut();
166 let rewriter = ir::Rewriter {
167 cell_map: rename_cells,
168 ..Default::default()
169 };
170 group
171 .assignments
172 .iter_mut()
173 .for_each(|assign| assign.for_each_port(|p| rewriter.get(p)));
174 }
175
176 self.invoke_map = invoke_map;
177 }
178}
179
180impl Visitor for RegisterUnsharing {
181 fn start(
182 &mut self,
183 comp: &mut ir::Component,
184 sigs: &LibrarySignatures,
185 _comps: &[ir::Component],
186 ) -> VisResult {
187 self.bookkeeper = Bookkeeper::new(comp);
188 let mut builder = Builder::new(comp, sigs);
189 let rename_list = self.bookkeeper.create_new_regs(&mut builder);
191 self.bookkeeper.rename(comp, &rename_list);
193 Ok(Action::Continue)
194 }
195
196 fn invoke(
197 &mut self,
198 invoke: &mut ir::Invoke,
199 _comp: &mut ir::Component,
200 _sigs: &LibrarySignatures,
201 _comps: &[ir::Component],
202 ) -> VisResult {
203 let book = &mut self.bookkeeper;
204
205 if let Some(name) = book.analysis.meta.fetch_label(invoke) {
206 if let Some(rename_vec) = book.invoke_map.get_mut(name) {
208 let cell_map = std::mem::take(rename_vec);
209 let rewriter = ir::Rewriter {
210 cell_map,
211 ..Default::default()
212 };
213 rewriter.rewrite_invoke(invoke);
214 *rename_vec = rewriter.cell_map;
215 }
216 }
217
218 Ok(Action::Continue)
219 }
220
221 fn static_invoke(
222 &mut self,
223 invoke: &mut ir::StaticInvoke,
224 _comp: &mut ir::Component,
225 _sigs: &LibrarySignatures,
226 _comps: &[ir::Component],
227 ) -> VisResult {
228 let book = &mut self.bookkeeper;
229
230 if let Some(name) = book.analysis.meta.fetch_label_static(invoke) {
231 if let Some(rename_vec) = book.invoke_map.get_mut(name) {
233 let cell_map = std::mem::take(rename_vec);
234 let rewriter = ir::Rewriter {
235 cell_map,
236 ..Default::default()
237 };
238 rewriter.rewrite_static_invoke(invoke);
239 *rename_vec = rewriter.cell_map;
240 }
241 }
242
243 Ok(Action::Continue)
244 }
245}