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>(&self, cell: &Cell, meta: MetaItemRef<'a>, rewriter: &Rewriter<'a>) -> RewriteResult<'a>;
51}
52
53pub struct Rewriter<'a> {
54 design: &'a Design,
55 rules: &'a [&'a dyn RewriteRuleset],
56 processed: RefCell<HashSet<Net>>,
57 cache: RefCell<HashMap<Cell, Value>>,
58}
59
60impl<'a> Rewriter<'a> {
61 pub fn find_cell(&self, net: Net) -> RewriteNetSource<'a> {
62 if !self.processed.borrow().contains(&net) && !net.is_const() {
63 return RewriteNetSource::Opaque;
64 }
65 match self.design.find_new_cell(net) {
66 Ok((cell, meta, bit)) => RewriteNetSource::Cell(cell, meta, bit),
67 Err(trit) => RewriteNetSource::Const(trit),
68 }
69 }
70
71 fn process_cell(&self, cell: &Cell, meta: MetaItemRef<'a>) -> RewriteResult<'a> {
72 let mut replacement_cell = None;
73 let mut replacement_meta = None;
74 'outer: loop {
75 for &rule in self.rules {
76 let cur_cell = replacement_cell.as_ref().unwrap_or(cell);
77 let cur_meta = replacement_meta.unwrap_or(meta);
78 let _guard = self.design.use_metadata(cur_meta);
79 match rule.rewrite(cur_cell, cur_meta, self) {
80 RewriteResult::None => (),
81 RewriteResult::Cell(new_cell) => {
82 replacement_cell = Some(new_cell);
83 continue 'outer;
84 }
85 RewriteResult::CellMeta(new_cell, new_meta) => {
86 replacement_cell = Some(new_cell);
87 replacement_meta = Some(new_meta);
88 continue 'outer;
90 }
91 RewriteResult::Value(value) => {
92 return RewriteResult::Value(value);
93 }
94 }
95 }
96 break;
97 }
98 let cell = replacement_cell.as_ref().unwrap_or(cell);
99 if let Some(value) = self.cache.borrow().get(&cell) {
100 let meta = replacement_meta.unwrap_or(meta);
101 self.design.append_metadata_by_net(value[0], meta);
102 RewriteResult::Value(value.clone())
103 } else {
104 match (replacement_cell, replacement_meta) {
105 (None, _) => RewriteResult::None,
106 (Some(cell), None) => RewriteResult::Cell(cell),
107 (Some(cell), Some(meta)) => RewriteResult::CellMeta(cell, meta),
108 }
109 }
110 }
111
112 pub fn add_cell(&self, cell: Cell) -> Value {
113 self.add_cell_meta(cell, self.design.get_use_metadata())
114 }
115
116 pub fn add_cell_meta(&self, cell: Cell, meta: MetaItemRef<'_>) -> Value {
117 let (cell, meta) = match self.process_cell(&cell, meta) {
118 RewriteResult::None => (cell, meta),
119 RewriteResult::Cell(new_cell) => (new_cell, meta),
120 RewriteResult::CellMeta(new_cell, new_meta) => (new_cell, new_meta),
121 RewriteResult::Value(value) => return value,
122 };
123 let value = self.design.add_cell_with_metadata_ref(cell.clone(), meta);
124 for net in &value {
125 self.processed.borrow_mut().insert(net);
126 }
127 if !cell.has_effects(self.design) {
128 self.cache.borrow_mut().insert(cell, value.clone());
129 }
130 value
131 }
132
133 fn run(&mut self) {
134 let worklist = self.design.topo_sort();
135 for item in worklist {
136 match item {
137 TopoSortItem::Cell(cell_ref) => {
138 let output = cell_ref.output();
139 let mut cell = cell_ref.get().into_owned();
140 cell.visit_mut(|net| *net = self.design.map_net_new(*net));
141 match self.process_cell(&cell, cell_ref.metadata()) {
142 RewriteResult::None => {
143 if !cell.has_effects(self.design) {
144 self.cache.borrow_mut().insert(cell, output.clone());
145 }
146 for net in output {
147 self.processed.borrow_mut().insert(net);
148 }
149 }
150 RewriteResult::Cell(new_cell) => {
151 cell_ref.replace(new_cell.clone());
152 if !new_cell.has_effects(self.design) {
153 self.cache.borrow_mut().insert(new_cell, output.clone());
154 }
155 for net in output {
156 self.processed.borrow_mut().insert(net);
157 }
158 }
159 RewriteResult::CellMeta(new_cell, new_meta) => {
160 cell_ref.replace(new_cell.clone());
161 cell_ref.append_metadata(new_meta);
162 if !new_cell.has_effects(self.design) {
163 self.cache.borrow_mut().insert(new_cell, output.clone());
164 }
165 for net in output {
166 self.processed.borrow_mut().insert(net);
167 }
168 }
169 RewriteResult::Value(value) => {
170 assert_eq!(value.len(), output.len());
171 for (net, new_net) in output.iter().zip(value) {
172 self.design.replace_net(net, new_net);
173 self.processed.borrow_mut().insert(net);
174 }
175 cell_ref.unalive();
176 }
177 }
178 }
179 TopoSortItem::CellBit(cell, bit) => {
180 let mut slice = cell.get().slice(bit..bit + 1).unwrap();
181 slice.visit_mut(|net| *net = self.design.map_net_new(*net));
182 let new_value = self.add_cell_meta(slice, cell.metadata());
183 let net = cell.output()[bit];
184 self.design.replace_net(net, new_value[0]);
185 self.processed.borrow_mut().insert(net);
186 }
187 }
188 }
189 }
190}
191
192impl Design {
193 pub fn rewrite(&mut self, rules: &[&dyn RewriteRuleset]) {
194 assert!(!self.is_changed());
195 let mut rewriter = Rewriter {
196 design: self,
197 rules,
198 processed: RefCell::new(HashSet::new()),
199 cache: RefCell::new(HashMap::new()),
200 };
201 rewriter.run();
202 self.compact();
203 }
204}