Skip to main content

prjunnamed_netlist/
rewrite.rs

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