1use std::{
2 borrow::Cow,
3 cell::RefCell,
4 collections::{HashMap, HashSet},
5};
6
7use crate::{design::TopoSortItem, Cell, ControlNet, Design, MetaItemRef, Net, Trit, Value};
8
9pub enum RewriteResult<'a> {
10 None,
11 Cell(Cell),
12 CellMeta(Cell, MetaItemRef<'a>),
13 Value(Value),
14}
15
16impl From<Value> for RewriteResult<'_> {
17 fn from(value: Value) -> Self {
18 RewriteResult::Value(value)
19 }
20}
21
22impl From<Net> for RewriteResult<'_> {
23 fn from(net: Net) -> Self {
24 RewriteResult::Value(net.into())
25 }
26}
27
28impl From<ControlNet> for RewriteResult<'_> {
29 fn from(cnet: ControlNet) -> Self {
30 match cnet {
31 ControlNet::Pos(net) => RewriteResult::Value(net.into()),
32 ControlNet::Neg(net) => RewriteResult::Cell(Cell::Not(net.into())),
33 }
34 }
35}
36
37impl From<Cell> for RewriteResult<'_> {
38 fn from(cell: Cell) -> Self {
39 RewriteResult::Cell(cell)
40 }
41}
42
43pub enum RewriteNetSource<'a> {
44 Const(Trit),
45 Opaque,
46 Cell(Cow<'a, Cell>, MetaItemRef<'a>, usize),
47}
48
49pub trait RewriteRuleset {
50 fn rewrite<'a>(
51 &self,
52 cell: &Cell,
53 meta: MetaItemRef<'a>,
54 output: Option<&Value>,
55 rewriter: &Rewriter<'a>,
56 ) -> RewriteResult<'a> {
57 let _ = (cell, meta, output, rewriter);
58 RewriteResult::None
59 }
60 fn cell_added(&self, design: &Design, cell: &Cell, output: &Value) {
61 let _ = (design, cell, output);
62 }
63 fn net_replaced(&self, design: &Design, from: Net, to: Net) {
64 let _ = (design, from, to);
65 }
66}
67
68pub struct Rewriter<'a> {
69 design: &'a Design,
70 rules: &'a [&'a dyn RewriteRuleset],
71 processed: RefCell<HashSet<Net>>,
72 cache: RefCell<HashMap<Cell, Value>>,
73}
74
75impl<'a> Rewriter<'a> {
76 pub fn find_cell(&self, net: Net) -> RewriteNetSource<'a> {
77 if !self.processed.borrow().contains(&net) && !net.is_const() {
78 return RewriteNetSource::Opaque;
79 }
80 match self.design.find_new_cell(net) {
81 Ok((cell, meta, bit)) => RewriteNetSource::Cell(cell, meta, bit),
82 Err(trit) => RewriteNetSource::Const(trit),
83 }
84 }
85
86 fn process_cell(&self, cell: &Cell, meta: MetaItemRef<'a>, output: Option<&Value>) -> RewriteResult<'a> {
87 let mut replacement_cell = None;
88 let mut replacement_meta = None;
89 'outer: loop {
90 for &rule in self.rules {
91 let cur_cell = replacement_cell.as_ref().unwrap_or(cell);
92 let cur_meta = replacement_meta.unwrap_or(meta);
93 let _guard = self.design.use_metadata(cur_meta);
94 match rule.rewrite(cur_cell, cur_meta, output, self) {
95 RewriteResult::None => (),
96 RewriteResult::Cell(new_cell) => {
97 replacement_cell = Some(new_cell);
98 continue 'outer;
99 }
100 RewriteResult::CellMeta(new_cell, new_meta) => {
101 replacement_cell = Some(new_cell);
102 replacement_meta = Some(new_meta);
103 continue 'outer;
104 }
105 RewriteResult::Value(value) => {
106 return RewriteResult::Value(value);
107 }
108 }
109 }
110 break;
111 }
112 let cell = replacement_cell.as_ref().unwrap_or(cell);
113 if let Some(value) = self.cache.borrow().get(&cell) {
114 let meta = replacement_meta.unwrap_or(meta);
115 self.design.append_metadata_by_net(value[0], meta);
116 RewriteResult::Value(value.clone())
117 } else {
118 match (replacement_cell, replacement_meta) {
119 (None, _) => RewriteResult::None,
120 (Some(cell), None) => RewriteResult::Cell(cell),
121 (Some(cell), Some(meta)) => RewriteResult::CellMeta(cell, meta),
122 }
123 }
124 }
125
126 pub fn add_cell(&self, cell: Cell) -> Value {
127 self.add_cell_meta(cell, self.design.get_use_metadata())
128 }
129
130 pub fn add_cell_meta(&self, cell: Cell, meta: MetaItemRef<'_>) -> Value {
131 self.add_cell_meta_output(cell, meta, None)
132 }
133
134 fn add_cell_meta_output(&self, cell: Cell, meta: MetaItemRef<'_>, output: Option<&Value>) -> Value {
135 let (cell, meta) = match self.process_cell(&cell, meta, output) {
136 RewriteResult::None => (cell, meta),
137 RewriteResult::Cell(new_cell) => (new_cell, meta),
138 RewriteResult::CellMeta(new_cell, new_meta) => (new_cell, new_meta),
139 RewriteResult::Value(value) => return value,
140 };
141 let value = self.design.add_cell_with_metadata_ref(cell.clone(), meta);
142 for &rule in self.rules {
143 rule.cell_added(self.design, &cell, &value);
144 }
145 for net in &value {
146 self.processed.borrow_mut().insert(net);
147 }
148 if !cell.has_effects(self.design) {
149 self.cache.borrow_mut().insert(cell, value.clone());
150 }
151 value
152 }
153
154 fn run(&mut self) {
155 let worklist = self.design.topo_sort();
156 for item in worklist {
157 match item {
158 TopoSortItem::Cell(cell_ref) => {
159 let output = cell_ref.output();
160 let mut cell = cell_ref.get().into_owned();
161 cell.visit_mut(|net| *net = self.design.map_net_new(*net));
162 match self.process_cell(&cell, cell_ref.metadata(), Some(&output)) {
163 RewriteResult::None => {
164 for &rule in self.rules {
165 rule.cell_added(self.design, &cell, &output);
166 }
167 if !cell.has_effects(self.design) {
168 self.cache.borrow_mut().insert(cell, output.clone());
169 }
170 for net in output {
171 self.processed.borrow_mut().insert(net);
172 }
173 }
174 RewriteResult::Cell(new_cell) => {
175 cell_ref.replace(new_cell.clone());
176 for &rule in self.rules {
177 rule.cell_added(self.design, &new_cell, &output);
178 }
179 if !new_cell.has_effects(self.design) {
180 self.cache.borrow_mut().insert(new_cell, output.clone());
181 }
182 for net in output {
183 self.processed.borrow_mut().insert(net);
184 }
185 }
186 RewriteResult::CellMeta(new_cell, new_meta) => {
187 cell_ref.replace(new_cell.clone());
188 for &rule in self.rules {
189 rule.cell_added(self.design, &new_cell, &output);
190 }
191 cell_ref.append_metadata(new_meta);
192 if !new_cell.has_effects(self.design) {
193 self.cache.borrow_mut().insert(new_cell, output.clone());
194 }
195 for net in output {
196 self.processed.borrow_mut().insert(net);
197 }
198 }
199 RewriteResult::Value(value) => {
200 assert_eq!(value.len(), output.len());
201 for (net, new_net) in output.iter().zip(value) {
202 self.design.replace_net(net, new_net);
203 for &rule in self.rules {
204 rule.net_replaced(self.design, net, new_net);
205 }
206 self.processed.borrow_mut().insert(net);
207 }
208 cell_ref.unalive();
209 }
210 }
211 }
212 TopoSortItem::CellBit(cell, bit) => {
213 let mut slice = cell.get().slice(bit..bit + 1).unwrap();
214 slice.visit_mut(|net| *net = self.design.map_net_new(*net));
215 let net = cell.output()[bit];
216 let new_value = self.add_cell_meta_output(slice, cell.metadata(), Some(&net.into()));
217 let new_net = new_value[0];
218 self.design.replace_net(net, new_net);
219 for &rule in self.rules {
220 rule.net_replaced(self.design, net, new_net);
221 }
222 self.processed.borrow_mut().insert(net);
223 }
224 }
225 }
226 }
227}
228
229impl Design {
230 pub fn rewrite(&mut self, rules: &[&dyn RewriteRuleset]) {
231 assert!(!self.is_changed());
232 let mut rewriter = Rewriter {
233 design: self,
234 rules,
235 processed: RefCell::new(HashSet::new()),
236 cache: RefCell::new(HashMap::new()),
237 };
238 rewriter.run();
239 self.compact();
240 }
241}